Skip to content

Commit

Permalink
test: re-enable secure send e2e test (#4507)
Browse files Browse the repository at this point in the history
### Description

This PR:
- update e2e consts for addresses mapped to a phone number
- re-enable secure send tests, with contract-kit and viem
- update fund e2e job to also fund the wallet used for these tests (this
wallet needs to be verified in order to do phone number lookups, and
needs to be different to the default e2e test wallet so that code paths
for non-verified addresses can be tested). refactor here and there to
make it easier to read.

### Test plan

n/a

### Related issues

- Fixes RET-854

### Backwards compatibility

Y
  • Loading branch information
kathaypacific authored Nov 21, 2023
1 parent a8bc7c1 commit b661e99
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 166 deletions.
6 changes: 5 additions & 1 deletion e2e/scripts/check-e2e-wallet-balance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { E2E_TEST_WALLET } from './consts'
import { E2E_TEST_WALLET, E2E_TEST_WALLET_SECURE_SEND } from './consts'
import { checkBalance, getBalance } from './utils'
;(async () => {
console.log(E2E_TEST_WALLET)
console.table(await getBalance(E2E_TEST_WALLET))
await checkBalance(E2E_TEST_WALLET)

console.log(E2E_TEST_WALLET_SECURE_SEND)
console.table(await getBalance(E2E_TEST_WALLET_SECURE_SEND))
await checkBalance(E2E_TEST_WALLET_SECURE_SEND)
})()
2 changes: 2 additions & 0 deletions e2e/scripts/consts.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export const E2E_TEST_WALLET = '0x6131a6d616a4be3737b38988847270a64bc10caa'
export const E2E_TEST_WALLET_SECURE_SEND = '0x86b8f44386cb2d457db79c3dab8cf42f9d8a3fc0'
export const E2E_TEST_FAUCET = '0xe5F5363e31351C38ac82DBAdeaD91Fd5a7B08846'
export const REFILL_TOKENS = ['CELO', 'cUSD', 'cEUR']
131 changes: 78 additions & 53 deletions e2e/scripts/fund-e2e-accounts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { newKitFromWeb3, StableToken } from '@celo/contractkit'
import dotenv from 'dotenv'
import Web3 from 'web3'
import { E2E_TEST_FAUCET, E2E_TEST_WALLET } from './consts'
import {
E2E_TEST_FAUCET,
E2E_TEST_WALLET,
E2E_TEST_WALLET_SECURE_SEND,
REFILL_TOKENS,
} from './consts'
import { checkBalance, getBalance } from './utils'

dotenv.config({ path: `${__dirname}/../.env` })
Expand All @@ -11,10 +16,16 @@ const kit = newKitFromWeb3(web3)
const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!

;(async () => {
// Get E2E Test Wallet Balance & Valora Faucet Balance
const receivingBalance = await getBalance(E2E_TEST_WALLET)
const sendingBalance = (await getBalance(E2E_TEST_FAUCET)) ?? {}
console.table(await getBalance(E2E_TEST_FAUCET))
const walletsToBeFunded = [E2E_TEST_WALLET, E2E_TEST_WALLET_SECURE_SEND]
const walletBalances = await Promise.all(walletsToBeFunded.map(getBalance))
for (let i = 0; i < walletsToBeFunded.length; i++) {
console.log(`Initial balance for ${walletsToBeFunded[i]}:`)
console.table(walletBalances[i])
}

const faucetTokenBalances = (await getBalance(E2E_TEST_FAUCET)) ?? {}
console.log('Initial faucet balance:')
console.table(faucetTokenBalances)

// Connect Valora E2E Test Faucet - Private Key Stored in GitHub Secrets
kit.connection.addAccount(
Expand All @@ -30,24 +41,27 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
const ceurExchange = await kit.contracts.getExchange(StableToken.cEUR)

// Balance Faucet
let targetTokenRegex = /[cusd|celo|ceur]/gi
let balances = await getBalance(E2E_TEST_FAUCET)
let sum = 0
const numOfTokens = 3 // Only cusd, celo and ceur
for (let balance in balances) {
console.log(`${balance}: ${balances[balance]}`)
// Sum only the target balances
if (targetTokenRegex.test(balance)) sum += balances[balance]
}
let totalTokenHoldings = 0 // the absolute number of faucet tokens the faucet is holding
Object.entries(faucetTokenBalances).forEach(([tokenSymbol, tokenBalance]) => {
if (REFILL_TOKENS.includes(tokenSymbol)) {
totalTokenHoldings += tokenBalance
}
})
const targetFaucetTokenBalance = totalTokenHoldings / REFILL_TOKENS.length

for (let balance in balances) {
const target = sum / numOfTokens
if (balances[balance] >= sum / numOfTokens) {
const toSell = balances[balance] - target
console.log(toSell)
const amountToExchange = kit.web3.utils.toWei(`${toSell}`, 'ether')
console.log(`${balance} balance higher than ${sum / numOfTokens}`)
switch (balance) {
// Ensure that the faucet has enough balance for each refill tokens
for (const [tokenSymbol, tokenBalance] of Object.entries(faucetTokenBalances)) {
if (!REFILL_TOKENS.includes(tokenSymbol)) {
continue
}

if (tokenBalance >= targetFaucetTokenBalance) {
const sellAmount = tokenBalance - targetFaucetTokenBalance
const amountToExchange = kit.web3.utils.toWei(`${sellAmount}`, 'ether')
console.log(
`${tokenSymbol} balance is ${tokenBalance}, which is higher than target ${targetFaucetTokenBalance}. Selling ${sellAmount}.`
)
switch (tokenSymbol) {
case 'CELO':
try {
const celoApproveTx = await celoToken
Expand Down Expand Up @@ -98,10 +112,12 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
}
}
} else {
const toBuy = target - balances[balance]
const amountToExchange = kit.web3.utils.toWei(`${toBuy}`, 'ether')
console.log(`${balance} balance lower than ${sum / numOfTokens}`)
switch (balance) {
const buyAmount = targetFaucetTokenBalance - tokenBalance
const amountToExchange = kit.web3.utils.toWei(`${buyAmount}`, 'ether')
console.log(
`${tokenSymbol} balance is ${tokenBalance}, which is lower than target ${targetFaucetTokenBalance}. Buying ${buyAmount}.`
)
switch (tokenSymbol) {
case 'CELO':
try {
const celoApproveTx = await celoToken
Expand Down Expand Up @@ -155,42 +171,51 @@ const valoraTestFaucetSecret = process.env['TEST_FAUCET_SECRET']!
}

// Set Amount To Send
let amountToSend = web3.utils.toWei('100', 'ether')
const amountToSend = '100'
const amountToSendWei = web3.utils.toWei(amountToSend, 'ether')

// Loop through E2E Test Wallet Balance Object
for (const coin in receivingBalance) {
let tx: any
// Add funds if balance is less than 100 add 100
if (receivingBalance[coin] < 200 && sendingBalance[coin] > 100) {
switch (coin) {
case 'CELO':
tx = await celoToken
.transfer(E2E_TEST_WALLET, amountToSend)
.send({ from: E2E_TEST_FAUCET })
break
case 'cUSD':
tx = await cusdToken
.transfer(E2E_TEST_WALLET, amountToSend)
.send({ from: E2E_TEST_FAUCET })
break
case 'cEUR':
tx = await ceurToken
.transfer(E2E_TEST_WALLET, amountToSend)
.send({ from: E2E_TEST_FAUCET })
break
}
// Wait for the transactions to be processed
let receipt = await tx.waitReceipt()
for (let i = 0; i < walletsToBeFunded.length; i++) {
const walletAddress = walletsToBeFunded[i]
const walletBalance = walletBalances[i]
for (const tokenSymbol of REFILL_TOKENS) {
if (walletBalance && walletBalance[tokenSymbol] < 200) {
console.log(`Sending ${amountToSend} ${tokenSymbol} to ${walletAddress}`)
let tx: any
switch (tokenSymbol) {
case 'CELO':
tx = await celoToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
case 'cUSD':
tx = await cusdToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
case 'cEUR':
tx = await ceurToken
.transfer(walletAddress, amountToSendWei)
.send({ from: E2E_TEST_FAUCET })
break
}
const receipt = await tx.waitReceipt()

// Print Receipt
console.log(' Transaction receipt: %o', receipt)
console.log(
`Received tx hash ${receipt.transactionHash} for ${tokenSymbol} transfer to ${walletAddress}`
)
}
}
}
console.log('Finished funding wallets.')

// Log Balances
console.log('E2E Test Account:', E2E_TEST_WALLET)
console.table(await getBalance(E2E_TEST_WALLET))
console.log('E2E Test Account Secure Send:', E2E_TEST_WALLET_SECURE_SEND)
console.table(await getBalance(E2E_TEST_WALLET_SECURE_SEND))
console.log('Valora Test Facuet:', E2E_TEST_FAUCET)
console.table(await getBalance(E2E_TEST_FAUCET))

await checkBalance(E2E_TEST_WALLET)
await checkBalance(E2E_TEST_WALLET_SECURE_SEND)
})()
14 changes: 10 additions & 4 deletions e2e/scripts/utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { REFILL_TOKENS } from './consts'

export const Web3 = require('web3')
export const ContractKit = require('@celo/contractkit')
export const dotenv = require('dotenv')
export const web3 = new Web3('https://alfajores-forno.celo-testnet.org')
export const kit = ContractKit.newKitFromWeb3(web3)

export async function checkBalance(address: string, minBalance = 10) {
let balanceObject = await getBalance(address)
for (const balance in balanceObject) {
if (balanceObject[balance as keyof typeof balanceObject] < minBalance) {
export async function checkBalance(
address: string,
minBalance = 10,
tokenSymbols: string[] = REFILL_TOKENS
) {
const balance = (await getBalance(address)) ?? {}
for (const [tokenSymbol, tokenBalance] of Object.entries(balance)) {
if (tokenSymbols.includes(tokenSymbol) && tokenBalance < minBalance) {
throw new Error(
`${balance} balance of ${address} is below ${minBalance}. Please refill from the faucet https://celo.org/developers/faucet or run ./fund-e2e-accounts.ts if a Valora Dev.`
)
Expand Down
8 changes: 1 addition & 7 deletions e2e/src/Send.spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import SecureSend from './usecases/SecureSend'
import Send from './usecases/Send'
import { quickOnboarding } from './utils/utils'

describe('Given', () => {
beforeAll(async () => {
await quickOnboarding()
})

describe('Send', Send)
// TODO: unskip this test if we enable CPV in CI
describe.skip('SecureSend cUSD', SecureSend)
describe('SecureSend with CPV', SecureSend)
})
136 changes: 71 additions & 65 deletions e2e/src/usecases/SecureSend.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,92 @@
import { reloadReactNative } from '../utils/retries'
import {
SAMPLE_BACKUP_KEY_VERIFIED,
VERIFIED_PHONE_NUMBER,
SAMPLE_WALLET_ADDRESS_VERIFIED_2,
} from '../utils/consts'
import { launchApp } from '../utils/retries'
import {
addComment,
enterPinUiIfNecessary,
inputNumberKeypad,
scrollIntoView,
sleep,
quickOnboarding,
} from '../utils/utils'
const faker = require('@faker-js/faker')

const PHONE_NUMBER = '+12057368924'
const LAST_ACCOUNT_CHARACTERS = 'FD08'
const AMOUNT_TO_SEND = '0.1'
const AMOUNT_TO_SEND = '0.01'

export default SecureSend = () => {
beforeEach(async () => {
await reloadReactNative()
})

it('Send cUSD to phone number with multiple mappings', async () => {
let randomContent = faker.lorem.words()
await waitFor(element(by.id('HomeAction-Send')))
.toBeVisible()
.withTimeout(30000)
await element(by.id('HomeAction-Send')).tap()

// Look for an address and tap on it.
await element(by.id('SearchInput')).tap()
await element(by.id('SearchInput')).replaceText(PHONE_NUMBER)
await element(by.id('RecipientItem')).tap()
describe.each([{ web3Library: 'contract-kit' }, { web3Library: 'viem' }])(
'Secure send flow with phone number lookup (with $web3Library)',
({ web3Library }) => {
beforeAll(async () => {
// uninstall the app to remove secure send mapping
await device.uninstallApp()
await device.installApp()
await launchApp({
newInstance: true,
permissions: { notifications: 'YES', contacts: 'YES' },
launchArgs: {
statsigGateOverrides: `use_new_send_flow=false,use_viem_for_send=${
web3Library === 'viem'
}`,
},
})
await quickOnboarding(SAMPLE_BACKUP_KEY_VERIFIED)
})

// Select the currency
await waitFor(element(by.id('cUSDBalance')))
.toBeVisible()
.withTimeout(30 * 1000)
await element(by.id('cUSDBalance')).tap()
it('Send cUSD to phone number with multiple mappings', async () => {
let randomContent = faker.lorem.words()
await waitFor(element(by.id('HomeAction-Send')))
.toBeVisible()
.withTimeout(30000)
await element(by.id('HomeAction-Send')).tap()
await waitFor(element(by.id('SendSearchInput'))).toBeVisible()

// Enter the amount and review
await inputNumberKeypad(AMOUNT_TO_SEND)
await element(by.id('Review')).tap()
await element(by.id('SearchInput')).tap()
await element(by.id('SearchInput')).replaceText(VERIFIED_PHONE_NUMBER)
await element(by.id('RecipientItem')).tap()

// hack: we shouldn't need this but the test fails without
await sleep(3000)
// Select the currency
await waitFor(element(by.id('cUSDTouchable'))).toBeVisible()
await element(by.id('cUSDTouchable')).tap()

// Click Edit if confirm account isn't served
try {
await element(by.id('accountEditButton')).tap()
} catch {}
// Enter the amount and review
await inputNumberKeypad(AMOUNT_TO_SEND)
await element(by.id('Review')).tap()

// Use the last digits of the account to confirm the sender.
await waitFor(element(by.id('confirmAccountButton')))
.toBeVisible()
.withTimeout(30000)
await element(by.id('confirmAccountButton')).tap()
for (let index = 0; index < 4; index++) {
const character = LAST_ACCOUNT_CHARACTERS[index]
await element(by.id(`SingleDigitInput/digit${index}`)).replaceText(character)
}

// Scroll to see submit button
await scrollIntoView('Submit', 'KeyboardAwareScrollView', 50)
await element(by.id('ConfirmAccountButton')).tap()
// Use the last digits of the account to confirm the sender.
await waitFor(element(by.id('confirmAccountButton'))).toBeVisible()
await element(by.id('confirmAccountButton')).tap()
// TODO: test case for AddressValidationType.PARTIAL but relies on mapping phone number to another address with unique last 4 digits
// for (let index = 0; index < 4; index++) {
// const character = LAST_ACCOUNT_CHARACTERS[index]
// await element(by.id(`SingleDigitInput/digit${index}`)).replaceText(character)
// }
await element(by.id('ValidateRecipientAccount/TextInput')).replaceText(
SAMPLE_WALLET_ADDRESS_VERIFIED_2
)

// Write a comment.
await addComment(randomContent)
// Scroll to see submit button
await scrollIntoView('Submit', 'KeyboardAwareScrollView', 50)
await element(by.id('ConfirmAccountButton')).tap()

// Wait for the confirm button to be clickable. If it takes too long this test
// will be flaky :(
await sleep(3000)
// Write a comment.
await addComment(randomContent)

// Confirm and input PIN if necessary.
await element(by.id('ConfirmButton')).tap()
await enterPinUiIfNecessary()
// Confirm and input PIN if necessary.
await element(by.id('ConfirmButton')).tap()
await enterPinUiIfNecessary()

// Return to home screen.
await waitFor(element(by.id('HomeAction-Send')))
.toBeVisible()
.withTimeout(30 * 1000)
// Return to home screen.
await waitFor(element(by.id('HomeAction-Send')))
.toBeVisible()
.withTimeout(30 * 1000)

// TODO: See why these are taking so long in e2e tests to appear
// Look for the latest transaction and assert
// await waitFor(element(by.text(`${randomContent}`)))
// .toBeVisible()
// .withTimeout(60000)
})
await waitFor(element(by.text(`${randomContent}`)))
.toBeVisible()
.withTimeout(60000)
})
}
)
}
Loading

0 comments on commit b661e99

Please sign in to comment.