Skip to content

Commit

Permalink
Merge branch 'main' into slava/change-earn-flow
Browse files Browse the repository at this point in the history
  • Loading branch information
sviderock committed Dec 16, 2024
2 parents 95cf72b + 7eb98ed commit 7cdaac1
Show file tree
Hide file tree
Showing 51 changed files with 960 additions and 553 deletions.
33 changes: 15 additions & 18 deletions .github/workflows/e2e-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,21 @@ concurrency:
cancel-in-progress: true

jobs:
# TODO: enable once we have at least one android-api-level below
# android:
# name: Android
# strategy:
# max-parallel: 2
# fail-fast: false
# matrix:
# # TODO if/when more CI machines: enable Android sdk 21, 23, 29 and 31
# # 21 is failing 9 specs
# # 23 is failing ? spec(s)
# # 31 is failing ? spec(s)
# # 24 is currently failing all the time, disabling it for now
# # 30 is not included as it runs on the merge queue
# android-api-level: []
# uses: ./.github/workflows/e2e-android.yml
# with:
# android-api-level: ${{ matrix.android-api-level }}
# secrets: inherit
android:
name: Android
strategy:
max-parallel: 2
fail-fast: false
matrix:
# min supported API level is 24
# 24 is failing due to Let's Encrypt root certificate expiration
# 25 is failing (RET-1274)
# 26 is failing (RET-1275)
android-api-level: ['27']
uses: ./.github/workflows/e2e-android.yml
with:
android-api-level: ${{ matrix.android-api-level }}
secrets: inherit
ios:
name: iOS
strategy:
Expand Down
2 changes: 2 additions & 0 deletions __mocks__/@react-native-firebase/dynamic-links.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const getInitialLink = jest.fn()
const buildShortLink = jest.fn()
const buildLink = jest.fn()
const onLink = jest.fn()

export default function links() {
return {
getInitialLink,
buildShortLink,
buildLink,
onLink,
}
}
3 changes: 3 additions & 0 deletions __mocks__/clevertap-react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ export default {
setPushToken: jest.fn(),
createNotificationChannel: jest.fn(),
registerForPush: jest.fn(),
getInitialUrl: jest.fn(),
addListener: jest.fn(),
removeListener: jest.fn(),
}
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode appVersionCode
versionName "1.100.0"
versionName "1.101.0"
multiDexEnabled true
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ RELEASE_KEY_ALIAS=mobilestack-key-alias

# Setting this manually based on version number until we have this deploying via Cloud Build
# Example: v1.5.1 deployment number 1 = 1005001001 (1 005 001 001)
VERSION_CODE=1021071684
VERSION_CODE=1021071685
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
Expand Down
4 changes: 2 additions & 2 deletions e2e/src/Discover.spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import DappListDisplay from './usecases/DappListDisplay'
import { launchApp } from './utils/retries'
import { quickOnboarding, scrollIntoView, waitForElementByIdAndTap } from './utils/utils'
import { quickOnboarding, scrollIntoView, waitForElementById } from './utils/utils'

describe('Discover tab', () => {
beforeAll(async () => {
await quickOnboarding()
// Relaunch app to ensure dapp list loads
// Needed for e2e tests otherwise dapp list is not loaded on first pass
await launchApp()
await waitForElementByIdAndTap('Tab/Discover')
await waitForElementById('Tab/Discover', { tap: true })

await scrollIntoView('View All', 'DiscoverScrollView')
await element(by.text('View All')).tap()
Expand Down
36 changes: 18 additions & 18 deletions e2e/src/QRScanner.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { reloadReactNative } from './utils/retries'
import { quickOnboarding, waitForElementId } from './utils/utils'
import { quickOnboarding, waitForElementById } from './utils/utils'

describe('Given QR Scanner', () => {
beforeAll(async () => {
Expand All @@ -9,65 +9,65 @@ describe('Given QR Scanner', () => {
describe('When opening QR scanner', () => {
it('Then should display QR code', async () => {
await reloadReactNative()
await waitForElementId('HomeAction-Receive')
await waitForElementById('HomeAction-Receive')
await element(by.id('HomeAction-Receive')).tap()
await waitForElementId('QRCode')
await waitForElementById('QRCode')
await expect(element(by.id('QRCode'))).toBeVisible()
})

it('Then should be able to toggle camera', async () => {
await waitForElementId('Scan')
await waitForElementById('Scan')
await element(by.id('Scan')).tap()
await waitForElementId('CameraScanInfo')
await waitForElementById('CameraScanInfo')
await expect(element(by.id('CameraScanInfo'))).toBeVisible()
})

it('Then should be able to toggle to QR code', async () => {
await waitForElementId('My Code')
await waitForElementById('My Code')
await element(by.id('My Code')).tap()
await waitForElementId('QRCode')
await waitForElementById('QRCode')
await expect(element(by.id('QRCode'))).toBeVisible()
})

it('Then should be able to close QR code scanner', async () => {
await waitForElementId('Times')
await waitForElementById('Times')
await element(by.id('Times')).tap()
await waitForElementId('HomeAction-Send')
await waitForElementById('HomeAction-Send')
await expect(element(by.id('HomeAction-Send'))).toBeVisible()
})
})

describe("When 'scanning' QR", () => {
beforeEach(async () => {
await reloadReactNative()
await waitForElementId('HomeAction-Receive')
await waitForElementById('HomeAction-Receive')
await element(by.id('HomeAction-Receive')).tap()
await waitForElementId('Scan')
await waitForElementById('Scan')
await element(by.id('Scan')).tap()
await waitForElementId('CameraScanInfo')
await waitForElementById('CameraScanInfo')
await element(by.id('CameraScanInfo')).tap()
})

it('Then should be able to handle Celo pay QR', async () => {
await waitForElementId('ManualInput')
await waitForElementById('ManualInput')
await element(by.id('ManualInput')).replaceText(
'celo://wallet/pay?address=0xe5F5363e31351C38ac82DBAdeaD91Fd5a7B08846'
)
await waitForElementId('ManualSubmit')
await waitForElementById('ManualSubmit')
await element(by.id('ManualSubmit')).tap()

await waitForElementId('SendEnterAmount/AmountOptions')
await waitForElementById('SendEnterAmount/AmountOptions')
await element(by.text('Done')).tap() // dismiss the keyboard to reveal the proceed button
await expect(element(by.id('SendEnterAmount/ReviewButton'))).toBeVisible()
})

it('Then should handle address only QR', async () => {
await waitForElementId('ManualInput')
await waitForElementById('ManualInput')
await element(by.id('ManualInput')).replaceText('0xe5F5363e31351C38ac82DBAdeaD91Fd5a7B08846')
await waitForElementId('ManualSubmit')
await waitForElementById('ManualSubmit')
await element(by.id('ManualSubmit')).tap()

await waitForElementId('SendEnterAmount/AmountOptions')
await waitForElementById('SendEnterAmount/AmountOptions')
await element(by.text('Done')).tap() // dismiss the keyboard to reveal the proceed button
await expect(element(by.id('SendEnterAmount/ReviewButton'))).toBeVisible()
})
Expand Down
43 changes: 21 additions & 22 deletions e2e/src/usecases/Assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ import {
getDisplayAddress,
quickOnboarding,
scrollIntoViewByTestId,
waitForElementByIdAndTap,
waitForElementId,
waitForElementById,
} from '../utils/utils'

async function validateSendFlow(tokenSymbol) {
const recipientAddressDisplay = getDisplayAddress(DEFAULT_RECIPIENT_ADDRESS)
// navigate to send amount screen to ensure the expected token symbol is pre-selected
await waitForElementByIdAndTap('SendSelectRecipientSearchInput')
await waitForElementById('SendSelectRecipientSearchInput', { tap: true })
await element(by.id('SendSelectRecipientSearchInput')).replaceText(DEFAULT_RECIPIENT_ADDRESS)
await element(by.id('SendSelectRecipientSearchInput')).tapReturnKey()
await expect(element(by.text(recipientAddressDisplay)).atIndex(0)).toBeVisible()
await element(by.text(recipientAddressDisplay)).atIndex(0).tap()
await waitForElementByIdAndTap('SendOrInviteButton')
await waitForElementById('SendOrInviteButton', { tap: true })
await expect(
element(by.text(`${tokenSymbol} on Celo`).withAncestor(by.id('SendEnterAmount/TokenSelect')))
).toBeVisible()
Expand Down Expand Up @@ -89,84 +88,84 @@ export default Assets = () => {
})

it('navigates to wallet tab from home', async () => {
await waitForElementByIdAndTap('Tab/Wallet')
await waitForElementId('Assets/TabBar')
await waitForElementById('Tab/Wallet', { tap: true })
await waitForElementById('Assets/TabBar')
})

it('switching tabs displays corresponding assets', async () => {
await expect(element(by.id('TokenBalanceItem')).atIndex(0)).toBeVisible()
await element(by.id('Assets/TabBarItem')).atIndex(1).tap()
await waitForElementId('Assets/NoNfts')
await waitForElementById('Assets/NoNfts')
await element(by.id('Assets/TabBarItem')).atIndex(0).tap()
await expect(element(by.id('TokenBalanceItem')).atIndex(0)).toBeVisible()
})

describe.each(tokens)('For $symbol', ({ symbol, tokenId, learnMore, actions, moreActions }) => {
it('navigates to asset details on tapping asset', async () => {
await waitForElementByIdAndTap(`TokenBalanceItemTouchable/${tokenId}`)
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById(`TokenBalanceItemTouchable/${tokenId}`, { tap: true })
await waitForElementById('TokenDetails/AssetValue')
})

if (actions.includes('Send')) {
it('send action navigates to send flow', async () => {
await element(by.id('TokenDetails/Action/Send')).tap()
await validateSendFlow(symbol)
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById('TokenDetails/AssetValue')
})
}

if (actions.includes('Add')) {
it('add action navigates to add cico flow', async () => {
await element(by.id('TokenDetails/Action/Add')).tap()
await validateAddFlow(symbol)
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById('TokenDetails/AssetValue')
})
}

if (moreActions.includes('Send')) {
it('send action under more actions navigates to send flow', async () => {
await element(by.id('TokenDetails/Action/More')).tap()
await waitForElementByIdAndTap('TokenDetailsMoreActions/Send')
await waitForElementById('TokenDetailsMoreActions/Send', { tap: true })
await validateSendFlow(symbol)
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById('TokenDetails/AssetValue')
})
}

if (moreActions.includes('Add')) {
it('add action under more actions navigates to add cico flow', async () => {
await element(by.id('TokenDetails/Action/More')).tap()
await waitForElementByIdAndTap('TokenDetailsMoreActions/Add')
await waitForElementById('TokenDetailsMoreActions/Add', { tap: true })
await validateAddFlow(symbol)
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById('TokenDetails/AssetValue')
})
}

if (moreActions.includes('Withdraw')) {
it('withdraw action under more actions navigates to withdraw spend screen', async () => {
await element(by.id('TokenDetails/Action/More')).tap()
await waitForElementByIdAndTap('TokenDetailsMoreActions/Withdraw')
await waitForElementId('FiatExchangeTokenBalance')
await waitForElementById('TokenDetailsMoreActions/Withdraw', { tap: true })
await waitForElementById('FiatExchangeTokenBalance')
await element(by.id('BackChevron')).tap()
await waitForElementId('TokenDetails/AssetValue')
await waitForElementById('TokenDetails/AssetValue')
})
}

if (learnMore) {
it('learn more navigates to coingecko page', async () => {
await scrollIntoViewByTestId('TokenDetails/LearnMore', 'TokenDetailsScrollView')
await waitForElementByIdAndTap('TokenDetails/LearnMore')
await waitForElementId('RNWebView')
await waitForElementById('TokenDetails/LearnMore', { tap: true })
await waitForElementById('RNWebView')
await waitFor(element(by.text('www.coingecko.com')))
.toBeVisible()
.withTimeout(10 * 1000)
await element(by.id('WebViewScreen/CloseButton')).tap()
await waitForElementId('TokenBalanceItem')
await waitForElementById('TokenBalanceItem')
})
}

it('navigates back to Assets page', async () => {
await element(by.id('BackChevron')).tap()
await waitForElementId('Assets/TabBar')
await waitForElementById('Assets/TabBar')
})
})
})
Expand Down
22 changes: 11 additions & 11 deletions e2e/src/usecases/CeloEducation.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { celoEducation } from '../utils/celoEducation'
import { waitForElementByIdAndTap, waitForElementId } from '../utils/utils'
import { waitForElementById } from '../utils/utils'

const swipeThrough = async (direction = 'left', swipes = 3) => {
for (let i = 0; i < swipes; i++) {
Expand All @@ -10,11 +10,11 @@ const swipeThrough = async (direction = 'left', swipes = 3) => {
const tapThrough = async (direction = 'forward', steps = 3) => {
if (direction === 'forward') {
for (let i = 0; i < steps; i++) {
await waitForElementByIdAndTap('Education/progressButton')
await waitForElementById('Education/progressButton', { tap: true })
}
} else {
for (let i = 0; i < steps; i++) {
await waitForElementByIdAndTap('Education/BackIcon')
await waitForElementById('Education/BackIcon', { tap: true })
}
}
}
Expand All @@ -27,40 +27,40 @@ const progressButtonCheck = async (text = 'Next', timeout = 10 * 1000) => {

export default CeloEducation = () => {
beforeAll(async () => {
await waitForElementByIdAndTap('WalletHome/NotificationBell')
await waitForElementId('NotificationView/celo_asset_education')
await waitForElementById('WalletHome/NotificationBell', { tap: true })
await waitForElementById('NotificationView/celo_asset_education')
await element(
by.text('Learn More').withAncestor(by.id('NotificationView/celo_asset_education'))
).tap()
})

it('should be able to navigate with swipes', async () => {
await swipeThrough()
await waitForElementId('Education/BackIcon')
await waitForElementById('Education/BackIcon')
await progressButtonCheck('Done')
await swipeThrough('right')
await waitForElementId('Education/CloseIcon')
await waitForElementById('Education/CloseIcon')
await progressButtonCheck('Next')
})

it("should be able to navigate with 'Next' & 'Back' button taps", async () => {
await tapThrough()
await progressButtonCheck('Done')
await tapThrough('back')
await waitForElementId('Education/CloseIcon')
await waitForElementById('Education/CloseIcon')
await progressButtonCheck('Next')
})

it('should be able to close CELO education carousel', async () => {
await waitForElementByIdAndTap('Education/CloseIcon')
await waitForElementId('NotificationView/celo_asset_education')
await waitForElementById('Education/CloseIcon', { tap: true })
await waitForElementById('NotificationView/celo_asset_education')
})

it('should be able to complete CELO education carousel', async () => {
await element(
by.text('Learn More').withAncestor(by.id('NotificationView/celo_asset_education'))
).tap()
await celoEducation()
await waitForElementId('Tab/Home')
await waitForElementById('Tab/Home')
})
}
Loading

0 comments on commit 7cdaac1

Please sign in to comment.