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(e2e): add new account creation test for new tab and cloud backup #5142

Merged
merged 5 commits into from
Mar 22, 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: 2 additions & 0 deletions e2e/src/AccountSetup.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import NewAccountOnboarding from './usecases/NewAccountOnboarding'
import NewAccountOnboardingDrawer from './usecases/NewAccountOnboardingDrawer'
import RestoreAccountOnboarding from './usecases/RestoreAccountOnboarding'

describe('Account Setup', () => {
describe('New Account', NewAccountOnboarding)
describe('New Account Drawer', NewAccountOnboardingDrawer)
describe('Restore', RestoreAccountOnboarding)
})
55 changes: 31 additions & 24 deletions e2e/src/usecases/NewAccountOnboarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import {
scrollIntoView,
sleep,
waitForElementId,
waitForElementByIdAndTap,
navigateToSettings,
} from '../utils/utils'

import jestExpect from 'expect'

const quickEducation = async () => {
await element(by.id('DrawerItem/Recovery Phrase')).tap()
const startBackupFromNotifications = async () => {
await element(by.id('WalletHome/NotificationBell')).tap()
await element(by.text('Back up now')).tap()
await enterPinUi()
await waitForElementByIdAndTap('WalletSecurityPrimer/GetStarted')
await waitForElementByIdAndTap('keylessBackupIntro/RecoveryPhrase')
await element(by.id('SetUpAccountKey')).tap()

// Go through education
Expand All @@ -30,13 +35,6 @@ const arriveAtHomeScreen = async () => {
await expect(element(by.id('HomeAction-Send'))).toBeVisible()
}

const openHamburger = async () => {
// Able to open the drawer - testing https://github.com/valora-inc/wallet/issues/3043
await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await waitForElementId('Drawer/Header')
}

export default NewAccountOnboarding = () => {
let testRecoveryPhrase, testAccountAddress
beforeAll(async () => {
Expand All @@ -45,6 +43,9 @@ export default NewAccountOnboarding = () => {
await launchApp({
delete: true,
permissions: { notifications: 'YES', contacts: 'YES' },
launchArgs: {
statsigGateOverrides: `use_tab_navigator=true,show_cloud_account_backup_setup=true,show_cloud_account_backup_restore=true`,
},
})
await sleep(5000)
})
Expand Down Expand Up @@ -74,12 +75,14 @@ export default NewAccountOnboarding = () => {
// Arrived to Home screen
await arriveAtHomeScreen()

// Able to open the drawer
await openHamburger()
// Able to open the profile / menu
await waitForElementByIdAndTap('WalletHome/AccountCircle')
await waitForElementId('ProfileMenu/Settings')
await element(by.id('Times')).tap()
})

it('Should be able to exit recovery phrase flow', async () => {
await quickEducation()
await startBackupFromNotifications()
await waitFor(element(by.text('Cancel')))
.toBeVisible()
.withTimeout(10 * 1000)
Expand All @@ -96,8 +99,7 @@ export default NewAccountOnboarding = () => {
})

it('Setup Recovery Phrase', async () => {
await openHamburger()
await quickEducation()
await startBackupFromNotifications()

const attributes = await element(by.id('AccountKeyWordsContainer')).getAttributes()
testRecoveryPhrase = attributes.label
Expand All @@ -121,20 +123,22 @@ export default NewAccountOnboarding = () => {
})

it('Account Address shown in drawer menu', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: no longer drawer menu.

await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await waitForElementByIdAndTap('WalletHome/AccountCircle')
await scrollIntoView('Account Address', 'SettingsScrollView')
const accountAddressElement = await element(by.id('AccountNumber')).getAttributes()
const accountAddressText = accountAddressElement.text.replace(/\s/g, '')
testAccountAddress = accountAddressText
jestExpect(testAccountAddress).toMatch(/0x[0-9a-fA-F]{40}/)
await element(by.id('Times')).tap()
})

// After quiz completion recovery phrase should only be shown in settings
// After quiz completion recovery phrase should only be shown in settings and
// not in notifications
it('Recovery phrase only shown in settings', async () => {
await expect(element(by.id('DrawerItem/Recovery Phrase'))).not.toExist()
await waitForElementId('DrawerItem/Settings')
await element(by.id('DrawerItem/Settings')).tap()
await element(by.id('WalletHome/NotificationBell')).tap()
await expect(element(by.text('Back up now'))).not.toExist()
await element(by.id('BackChevron')).tap()
await navigateToSettings('tab')
await waitForElementId('RecoveryPhrase')
await element(by.id('RecoveryPhrase')).tap()
await enterPinUi()
Expand All @@ -153,10 +157,13 @@ export default NewAccountOnboarding = () => {
it('Should be able to restore newly created account', async () => {
await device.uninstallApp()
await device.installApp()
await launchApp()
await quickOnboarding(testRecoveryPhrase)
await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await launchApp({
launchArgs: {
statsigGateOverrides: `use_tab_navigator=true,show_cloud_account_backup_setup=true,show_cloud_account_backup_restore=true`,
},
})
await quickOnboarding(testRecoveryPhrase, true)
await waitForElementByIdAndTap('WalletHome/AccountCircle')
await scrollIntoView('Account Address', 'SettingsScrollView')
const addressString = '0x ' + getAddressChunks(testAccountAddress).join(' ')
await expect(element(by.text(addressString))).toBeVisible()
Expand Down
164 changes: 164 additions & 0 deletions e2e/src/usecases/NewAccountOnboardingDrawer.js
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is exactly NewAccountOnboarding.js before the above changes

Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { getAddressChunks } from '@celo/utils/lib/address'
import { EXAMPLE_NAME } from '../utils/consts'
import { launchApp } from '../utils/retries'
import {
completeProtectWalletScreen,
enterPinUi,
quickOnboarding,
scrollIntoView,
sleep,
waitForElementId,
} from '../utils/utils'

import jestExpect from 'expect'

const quickEducation = async () => {
await element(by.id('DrawerItem/Recovery Phrase')).tap()
await enterPinUi()
await element(by.id('SetUpAccountKey')).tap()

// Go through education
for (let i = 0; i < 4; i++) {
await element(by.id('Education/progressButton')).tap()
}

await expect(element(by.id('AccountKeyWordsContainer'))).toBeVisible()
}

const arriveAtHomeScreen = async () => {
// Arrived to Home screen
await expect(element(by.id('HomeAction-Send'))).toBeVisible()
}

const openHamburger = async () => {
// Able to open the drawer - testing https://github.com/valora-inc/wallet/issues/3043
await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await waitForElementId('Drawer/Header')
}

export default NewAccountOnboarding = () => {
let testRecoveryPhrase, testAccountAddress
beforeAll(async () => {
await device.terminateApp()
await sleep(5000)
await launchApp({
delete: true,
permissions: { notifications: 'YES', contacts: 'YES' },
})
await sleep(5000)
})

it('Create a new account', async () => {
await element(by.id('CreateAccountButton')).tap()

// Accept Terms
await element(by.id('scrollView')).scrollTo('bottom')
await expect(element(by.id('AcceptTermsButton'))).toBeVisible()
await element(by.id('AcceptTermsButton')).tap()

// Set name and number
await element(by.id('NameEntry')).replaceText(EXAMPLE_NAME)
await element(by.id('NameAndPictureContinueButton')).tap()

// Set & Verify pin
await enterPinUi()
await enterPinUi()

// Protect Wallet screen
await completeProtectWalletScreen()

// Skip Phone Number verification
await element(by.id('PhoneVerificationSkipHeader')).tap()

// Arrived to Home screen
await arriveAtHomeScreen()

// Able to open the drawer
await openHamburger()
})

it('Should be able to exit recovery phrase flow', async () => {
await quickEducation()
await waitFor(element(by.text('Cancel')))
.toBeVisible()
.withTimeout(10 * 1000)
await element(by.text('Cancel')).tap()

// Cancel modal is shown
await waitFor(element(by.text('Set Up Later')))
.toBeVisible()
.withTimeout(10 * 1000)
await element(by.text('Set Up Later')).tap()

// App doesn't crash and we arrive at the home screen
await arriveAtHomeScreen()
})

it('Setup Recovery Phrase', async () => {
await openHamburger()
await quickEducation()

const attributes = await element(by.id('AccountKeyWordsContainer')).getAttributes()
testRecoveryPhrase = attributes.label

await element(by.id('backupKeySavedSwitch')).longPress()
await element(by.id('backupKeyContinue')).tap()
for (const word of testRecoveryPhrase.split(' ')) {
await element(by.id(`backupQuiz/${word}`)).tap()
}
await element(by.id('QuizSubmit')).tap()

// Backup complete screen is served
await waitFor(element(by.id('BackupComplete')))
.toBeVisible()
.withTimeout(10 * 1000)

// Navigated to Home screen
await waitFor(element(by.id('HomeAction-Send')))
.toBeVisible()
.withTimeout(10 * 1000)
})

it('Account Address shown in drawer menu', async () => {
await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await scrollIntoView('Account Address', 'SettingsScrollView')
const accountAddressElement = await element(by.id('AccountNumber')).getAttributes()
const accountAddressText = accountAddressElement.text.replace(/\s/g, '')
testAccountAddress = accountAddressText
jestExpect(testAccountAddress).toMatch(/0x[0-9a-fA-F]{40}/)
})

// After quiz completion recovery phrase should only be shown in settings
it('Recovery phrase only shown in settings', async () => {
await expect(element(by.id('DrawerItem/Recovery Phrase'))).not.toExist()
await waitForElementId('DrawerItem/Settings')
await element(by.id('DrawerItem/Settings')).tap()
await waitForElementId('RecoveryPhrase')
await element(by.id('RecoveryPhrase')).tap()
await enterPinUi()
await waitForElementId('AccountKeyWordsContainer')
})

// Based off the flag set in src/firebase/remoteConfigValuesDefaults.e2e.ts
// We can only test one path 12 or 24 words as we cannot flip the flag after the build step
it('Recovery phrase has 12 words', async () => {
const recoveryPhraseContainer = await element(by.id('AccountKeyWordsContainer')).getAttributes()
const recoveryPhraseText = recoveryPhraseContainer.label
jestExpect(recoveryPhraseText.split(' ').length).toBe(12)
jestExpect(recoveryPhraseText).toBe(testRecoveryPhrase)
})

it('Should be able to restore newly created account', async () => {
await device.uninstallApp()
await device.installApp()
await launchApp()
await quickOnboarding(testRecoveryPhrase)
await waitForElementId('Hamburger')
await element(by.id('Hamburger')).tap()
await scrollIntoView('Account Address', 'SettingsScrollView')
const addressString = '0x ' + getAddressChunks(testAccountAddress).join(' ')
await expect(element(by.text(addressString))).toBeVisible()
})
}
4 changes: 3 additions & 1 deletion e2e/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export function quote(s) {
return device.getPlatform() === 'ios' ? s : `"${s}"`
}

export async function quickOnboarding(mnemonic = SAMPLE_BACKUP_KEY) {
export async function quickOnboarding(mnemonic = SAMPLE_BACKUP_KEY, cloudBackupEnabled = false) {
try {
// Tap Restore Account
await element(by.id('RestoreAccountButton')).tap()
Expand All @@ -175,6 +175,8 @@ export async function quickOnboarding(mnemonic = SAMPLE_BACKUP_KEY) {
// Verify pin
await enterPinUi()

if (cloudBackupEnabled) await waitForElementByIdAndTap('ImportSelect/Mnemonic')

// Restore existing wallet
await waitFor(element(by.id('connectingToCelo')))
.not.toBeVisible()
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-native": "^4.0.0",
"ethers": "^5.7.2",
"expect": "^29.7.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixes a knip error. We use expect directly in e2e tests. It was previously a transitive dependency from jest which knip doesn't allow https://knip.dev/guides/handling-issues#unlisted-dependencies

"husky": "^3.0.0",
"jest": "^29.6.2",
"jest-circus": "^29.6.2",
Expand Down
Loading
Loading