diff --git a/.depcheckrc.yml b/.depcheckrc.yml index c90705901b4..f51f487fd9b 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -2,7 +2,6 @@ ignores: - '@metamask/oss-attribution-generator' - 'webpack-cli' - - '@react-native-community/datetimepicker' - '@react-native-community/slider' - 'patch-package' - '@lavamoat/allow-scripts' diff --git a/.detoxrc.js b/.detoxrc.js index d637d3c937c..ad953511261 100644 --- a/.detoxrc.js +++ b/.detoxrc.js @@ -26,7 +26,7 @@ module.exports = { configurations: { 'ios.sim.apiSpecs': { device: 'ios.simulator', - app: 'ios.debug', + app: 'ios.qa', testRunner: { args: { "$0": "node e2e/api-specs/run-api-spec-tests.js", @@ -41,10 +41,9 @@ module.exports = { device: 'ios.simulator', app: 'ios.release', }, - // because e2e run on debug mode in bitrise - 'android.emu.bitrise.debug': { - device: 'android.bitrise.emulator', - app: 'android.bitrise.debug', + 'ios.sim.qa': { + device: 'ios.simulator', + app: 'ios.qa', }, 'android.emu.debug': { @@ -86,32 +85,21 @@ module.exports = { binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/MetaMask.app', build: 'yarn start:ios:e2e', }, - 'ios.release': { + 'ios.qa': { type: 'ios.app', binaryPath: - 'ios/build/Build/Products/Release-iphonesimulator/MetaMask.app', - build: "METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='production' yarn build:ios:release:e2e", - }, - 'android.bitrise.debug': { - type: 'android.apk', - binaryPath: 'android/app/build/outputs/apk/prod/debug/app-prod-debug.apk', - build: 'yarn start:android:e2e', + 'ios/build/Build/Products/Release-iphonesimulator/MetaMask-QA.app', + build: "METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:ios:qa", }, 'android.debug': { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/prod/debug/app-prod-debug.apk', build: 'yarn start:android:e2e', }, - 'android.release': { - type: 'android.apk', - binaryPath: - 'android/app/build/outputs/apk/prod/release/app-prod-release.apk', - build: "METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='production' yarn build:android:release:e2e", - }, 'android.qa': { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/qa/release/app-qa-release.apk', - build: "METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:qa:e2e", + build: "METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:qa", }, }, }; diff --git a/.github/scripts/get-next-semver-version.sh b/.github/scripts/get-next-semver-version.sh index 8107471978e..552e1fa7061 100755 --- a/.github/scripts/get-next-semver-version.sh +++ b/.github/scripts/get-next-semver-version.sh @@ -16,7 +16,7 @@ VERSION_BRANCHES=$(git branch -r | grep -o 'release/[0-9]*\.[0-9]*\.[0-9]*' | gr VERSION_TAGS=$(git tag | grep -o 'v[0-9]*\.[0-9]*\.[0-9]*' | grep -o '[0-9]*\.[0-9]*\.[0-9]*' | sort --version-sort | tail -n 1) # Get the version from package.json -VERSION_PACKAGE=$(node -p "require('./package.json').version") +VERSION_PACKAGE=$(node -p "require('../../package.json').version") # Compare versions and keep the highest one HIGHEST_VERSION=$(printf "%s\n%s\n%s" "$VERSION_BRANCHES" "$VERSION_TAGS" "$VERSION_PACKAGE" | sort --version-sort | tail -n 1) diff --git a/android/app/build.gradle b/android/app/build.gradle index 7978222f4a7..80ffad8fa28 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -229,7 +229,7 @@ android { release { manifestPlaceholders.isDebug = false minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro", "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro", "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules.pro" } } diff --git a/app/component-library/components-temp/Accounts/AccountBase/AccountBase.styles.ts b/app/component-library/components-temp/Accounts/AccountBase/AccountBase.styles.ts index cda7d7fe248..f755c07b3eb 100644 --- a/app/component-library/components-temp/Accounts/AccountBase/AccountBase.styles.ts +++ b/app/component-library/components-temp/Accounts/AccountBase/AccountBase.styles.ts @@ -29,7 +29,6 @@ const styleSheet = StyleSheet.create({ justifyContent: 'flex-start', }, accountNameLabelText: { - marginLeft: 4, paddingHorizontal: 8, borderWidth: 1, borderRadius: 8, diff --git a/app/component-library/components-temp/Accounts/AccountBase/AccountBase.tsx b/app/component-library/components-temp/Accounts/AccountBase/AccountBase.tsx index 14f619c98e0..88e0f809d05 100644 --- a/app/component-library/components-temp/Accounts/AccountBase/AccountBase.tsx +++ b/app/component-library/components-temp/Accounts/AccountBase/AccountBase.tsx @@ -49,15 +49,17 @@ const AccountBase = ({ {accountName} - {accountTypeLabel && ( + + {accountTypeLabel && ( + {strings(accountTypeLabel)} - )} + )} diff --git a/app/components/Base/Title/Title.tsx b/app/components/Base/Title/Title.tsx index ea062e2de3b..71f8eb5ccc4 100644 --- a/app/components/Base/Title/Title.tsx +++ b/app/components/Base/Title/Title.tsx @@ -18,12 +18,12 @@ const Title: React.FC = ({ return ( ); diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index a587ef6c3ae..8f424320041 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -131,6 +131,7 @@ import OptionsSheet from '../../UI/SelectOptionSheet/OptionsSheet'; import FoxLoader from '../../../components/UI/FoxLoader'; import { AppStateEventProcessor } from '../../../core/AppStateEventListener'; import MultiRpcModal from '../../../components/Views/MultiRpcModal/MultiRpcModal'; +import { trace, TraceName, TraceOperation } from '../../../util/trace'; const clearStackNavigatorOptions = { headerShown: false, @@ -354,7 +355,15 @@ const App = (props) => { setOnboarded(!!existingUser); try { if (existingUser) { - await Authentication.appTriggeredAuth(); + await trace( + { + name: TraceName.BiometricAuthentication, + op: TraceOperation.BiometricAuthentication, + }, + async () => { + await Authentication.appTriggeredAuth(); + }, + ); // we need to reset the navigator here so that the user cannot go back to the login screen navigator.reset({ routes: [{ name: Routes.ONBOARDING.HOME_NAV }] }); } else { diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js index 0d0a523f547..32a35e27754 100644 --- a/app/components/Nav/Main/index.js +++ b/app/components/Nav/Main/index.js @@ -492,7 +492,6 @@ const MainFlow = () => ( mode={'modal'} screenOptions={{ headerShown: false, - cardStyle: { backgroundColor: importedColors.transparent }, }} > diff --git a/app/components/UI/Name/Name.tsx b/app/components/UI/Name/Name.tsx index 1f338a8b0a7..5e44d36fe8f 100644 --- a/app/components/UI/Name/Name.tsx +++ b/app/components/UI/Name/Name.tsx @@ -47,11 +47,21 @@ const UnknownEthereumAddress: React.FC<{ address: string }> = ({ address }) => { ); }; -const Name: React.FC = ({ type, value }) => { +const Name: React.FC = ({ + chainId, + preferContractSymbol, + type, + value, +}) => { if (type !== NameType.EthereumAddress) { throw new Error('Unsupported NameType: ' + type); } - const displayName = useDisplayName(type, value); + const displayName = useDisplayName( + type, + value, + chainId, + preferContractSymbol, + ); const { styles } = useStyles(styleSheet, { displayNameVariant: displayName.variant, }); diff --git a/app/components/UI/Name/Name.types.ts b/app/components/UI/Name/Name.types.ts index 007a5077b06..45f7f241b6f 100644 --- a/app/components/UI/Name/Name.types.ts +++ b/app/components/UI/Name/Name.types.ts @@ -1,4 +1,5 @@ import { ViewProps } from 'react-native'; +import { Hex } from '@metamask/utils'; /** * The name types supported by the NameController. @@ -11,6 +12,8 @@ export enum NameType { } export interface NameProperties extends ViewProps { + chainId?: Hex; + preferContractSymbol?: boolean; type: NameType; value: string; } diff --git a/app/components/UI/Navbar/index.js b/app/components/UI/Navbar/index.js index 8127d67f23c..fd8aa98b1f8 100644 --- a/app/components/UI/Navbar/index.js +++ b/app/components/UI/Navbar/index.js @@ -1824,34 +1824,61 @@ export const getSettingsNavigationOptions = (title, themeColors) => { }; }; -export function getStakingNavbar(title, navigation, themeColors) { +/** + * + * @param {String} title - Navbar Title. + * @param {NavigationProp} navigation Navigation object returned from useNavigation hook. + * @param {ThemeColors} themeColors theme.colors returned from useStyles hook. + * @param {{ backgroundColor?: string, hasCancelButton?: boolean, hasBackButton?: boolean }} [options] - Optional options for navbar. + * @returns Staking Navbar Component. + */ +export function getStakingNavbar(title, navigation, themeColors, options) { + const { hasBackButton = true, hasCancelButton = true } = options ?? {}; + const innerStyles = StyleSheet.create({ + headerStyle: { + backgroundColor: + options?.backgroundColor ?? themeColors.background.default, + shadowOffset: null, + }, + headerLeft: { + marginHorizontal: 16, + }, headerButtonText: { color: themeColors.primary.default, fontSize: 14, ...fontStyles.normal, }, - headerStyle: { - backgroundColor: themeColors.background.default, - shadowColor: importedColors.transparent, - elevation: 0, - }, }); + + function navigationPop() { + navigation.goBack(); + } + return { headerTitle: () => ( - - ), - headerLeft: () => , - headerRight: () => ( - navigation.dangerouslyGetParent()?.pop()} - style={styles.closeButton} - > - - {strings('navigation.cancel')} - - + {title} ), headerStyle: innerStyles.headerStyle, + headerLeft: () => + hasBackButton ? ( + + ) : null, + headerRight: () => + hasCancelButton ? ( + navigation.dangerouslyGetParent()?.pop()} + style={styles.closeButton} + > + + {strings('navigation.cancel')} + + + ) : null, }; } diff --git a/app/components/UI/Notification/NotificationMenuItem/Content.test.tsx b/app/components/UI/Notification/NotificationMenuItem/Content.test.tsx index 1a65102a1ad..c227b206ec5 100644 --- a/app/components/UI/Notification/NotificationMenuItem/Content.test.tsx +++ b/app/components/UI/Notification/NotificationMenuItem/Content.test.tsx @@ -5,14 +5,15 @@ import NotificationContent from './Content'; describe('NotificationContent', () => { const title = 'Welcome to the new Test!'; - const createdAt = '2024-04-26T16:35:03.147606Z'; + const yesterday = new Date().setDate(new Date().getDate() - 1); + const createdAt = new Date(yesterday).toISOString(); // Relative date: one day before current date const description = { start: 'We are excited to announce the launch of our brand new website and app!', end: 'Ethereum', }; - it('renders correctly', () => { + it('render matches snapshot', () => { const { toJSON } = renderWithProvider( - 6 months ago + Yesterday @@ -1241,24 +1231,14 @@ exports[`BuildQuote View Crypto Currency Data renders a special error page if cr accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -1952,24 +1932,14 @@ exports[`BuildQuote View Crypto Currency Data renders an error page when there i accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -3582,24 +3552,14 @@ exports[`BuildQuote View Fiat Currency Data renders an error page when there is accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -5212,24 +5172,14 @@ exports[`BuildQuote View Payment Method Data renders an error page when there is accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -6842,24 +6792,14 @@ exports[`BuildQuote View Regions data renders an error page when there is a regi accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -14562,24 +14502,14 @@ exports[`BuildQuote View renders correctly when sdkError is present 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -15244,24 +15174,14 @@ exports[`BuildQuote View renders correctly when sdkError is present 2`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap b/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap index e5caeaa4a0f..40c849bc25a 100644 --- a/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap +++ b/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap @@ -2296,24 +2296,14 @@ exports[`GetStarted renders correctly when sdkError is present 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap index 92cb998fc5d..da5eb51bb0e 100644 --- a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap +++ b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap @@ -8400,24 +8400,14 @@ exports[`NetworkSwitcher View renders correctly with errors 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -9059,24 +9049,14 @@ exports[`NetworkSwitcher View renders correctly with errors 2`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -9718,24 +9698,14 @@ exports[`NetworkSwitcher View renders correctly with no data 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap index b6ab62534d5..06315a15e53 100644 --- a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap +++ b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap @@ -8415,24 +8415,14 @@ exports[`OrderDetails renders an error screen if a CREATED order cannot be polle accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap b/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap index 5c0641f5780..9f335593db4 100644 --- a/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap +++ b/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap @@ -4697,24 +4697,14 @@ exports[`PaymentMethods View renders correctly with empty data 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -5381,24 +5371,14 @@ exports[`PaymentMethods View renders correctly with empty data for sell 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -6065,24 +6045,14 @@ exports[`PaymentMethods View renders correctly with error 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -9509,24 +9479,14 @@ exports[`PaymentMethods View renders correctly with sdkError 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index b66ad3b7fd6..7a16475b13c 100644 --- a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -1095,24 +1095,14 @@ exports[`Quotes renders animation on first fetching 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -6515,24 +6505,14 @@ exports[`Quotes renders correctly after animation without quotes 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -7283,24 +7263,14 @@ exports[`Quotes renders correctly when fetching quotes errors 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -8051,24 +8021,14 @@ exports[`Quotes renders correctly with sdkError 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -8819,24 +8779,14 @@ exports[`Quotes renders quotes expired screen 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap b/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap index d513139d165..4d872304a48 100644 --- a/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap @@ -1934,24 +1934,14 @@ exports[`Regions View renders correctly with error 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > @@ -3204,24 +3194,14 @@ exports[`Regions View renders correctly with sdkError 1`] = ` accessibilityRole="text" style={ { - "0": { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 18, - "fontWeight": "600", - "marginVertical": 3, - }, - "1": { - "textAlign": "center", - }, - "2": undefined, - "3": undefined, "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 18, + "fontWeight": "600", "letterSpacing": 0, "lineHeight": 22, + "marginVertical": 3, + "textAlign": "center", } } > diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx index 96edaf2b2a3..534c0d58c50 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx @@ -63,9 +63,10 @@ const AssetPill: React.FC = ({ asset }) => { ) : ( )} diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.styles.ts b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.styles.ts new file mode 100644 index 00000000000..d351fc7302a --- /dev/null +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.styles.ts @@ -0,0 +1,23 @@ +import type { Theme } from '../../../../../util/theme/models'; +import { StyleSheet } from 'react-native'; + +const stylesSheet = (params: { theme: Theme }) => { + const { theme } = params; + const { colors } = theme; + + return StyleSheet.create({ + mainContainer: { + flex: 1, + paddingTop: 8, + paddingHorizontal: 16, + backgroundColor: colors.background.alternative, + justifyContent: 'space-between', + }, + cardsContainer: { + paddingTop: 16, + gap: 8, + }, + }); +}; + +export default stylesSheet; diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx new file mode 100644 index 00000000000..109fe3e7fac --- /dev/null +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import renderWithProvider from '../../../../../util/test/renderWithProvider'; +import StakeConfirmationView from './StakeConfirmationView'; +import { Image } from 'react-native'; +import { createMockAccountsControllerState } from '../../../../../util/test/accountsControllerTestUtils'; +import { backgroundState } from '../../../../../util/test/initial-root-state'; +import configureMockStore from 'redux-mock-store'; +import { Provider } from 'react-redux'; +import { StakeConfirmationViewProps } from './StakeConfirmationView.types'; + +jest.mock('../../../../hooks/useIpfsGateway', () => jest.fn()); + +Image.getSize = jest.fn((_uri, success) => { + success(100, 100); // Mock successful response for ETH native Icon Image +}); + +const MOCK_ADDRESS_1 = '0x0'; +const MOCK_ADDRESS_2 = '0x1'; + +const MOCK_ACCOUNTS_CONTROLLER_STATE = createMockAccountsControllerState([ + MOCK_ADDRESS_1, + MOCK_ADDRESS_2, +]); + +const mockStore = configureMockStore(); + +const mockInitialState = { + settings: {}, + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + }, + }, +}; +const store = mockStore(mockInitialState); + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest + .fn() + .mockImplementation((callback) => callback(mockInitialState)), +})); + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useNavigation: () => ({ + navigate: jest.fn(), + setOptions: jest.fn(), + }), + }; +}); + +describe('StakeConfirmationView', () => { + it('render matches snapshot', () => { + const props: StakeConfirmationViewProps = { + route: { + key: '1', + params: { amountWei: '3210000000000000', amountFiat: '7.46' }, + name: 'params', + }, + }; + + const { toJSON } = renderWithProvider( + + + , + ); + + expect(toJSON()).toMatchSnapshot(); + }); +}); diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx new file mode 100644 index 00000000000..2f1a4890286 --- /dev/null +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx @@ -0,0 +1,60 @@ +import React, { useEffect } from 'react'; +import { View } from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import { useStyles } from '../../../../hooks/useStyles'; +import { getStakingNavbar } from '../../../Navbar'; +import styleSheet from './StakeConfirmationView.styles'; +import TokenValueStack from '../../components/StakingConfirmation/TokenValueStack/TokenValueStack'; +import AccountHeaderCard from '../../components/StakingConfirmation/AccountHeaderCard/AccountHeaderCard'; +import RewardsCard from '../../components/StakingConfirmation/RewardsCard/RewardsCard'; +import ConfirmationFooter from '../../components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter'; +import { StakeConfirmationViewProps } from './StakeConfirmationView.types'; +import { MOCK_GET_VAULT_RESPONSE } from '../../components/StakingBalance/mockData'; +import { strings } from '../../../../../../locales/i18n'; + +const MOCK_REWARD_DATA = { + REWARDS: { + ETH: '0.13 ETH', + FIAT: '$334.93', + }, +}; + +const MOCK_STAKING_CONTRACT_NAME = 'MM Pooled Staking'; + +const StakeConfirmationView = ({ route }: StakeConfirmationViewProps) => { + const navigation = useNavigation(); + + const { styles, theme } = useStyles(styleSheet, {}); + + useEffect(() => { + navigation.setOptions( + getStakingNavbar(strings('stake.stake'), navigation, theme.colors, { + backgroundColor: theme.colors.background.alternative, + hasCancelButton: false, + }), + ); + }, [navigation, theme.colors]); + + return ( + + + + + + + + + + + ); +}; + +export default StakeConfirmationView; diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts new file mode 100644 index 00000000000..8c723135f4f --- /dev/null +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.types.ts @@ -0,0 +1,10 @@ +import { RouteProp } from '@react-navigation/native'; + +interface StakeConfirmationViewRouteParams { + amountWei: string; + amountFiat: string; +} + +export interface StakeConfirmationViewProps { + route: RouteProp<{ params: StakeConfirmationViewRouteParams }, 'params'>; +} diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap b/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap new file mode 100644 index 00000000000..9d14c100f63 --- /dev/null +++ b/app/components/UI/Stake/Views/StakeConfirmationView/__snapshots__/StakeConfirmationView.test.tsx.snap @@ -0,0 +1,1424 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StakeConfirmationView render matches snapshot 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + 0.00321 + + ETH + + + $7.46 + + + + + + + + + + + + Staking from + + + + + + + + + + + + + + + + + + + + + + + Account 1 + + + + + + + + + + + + + Interacting with + + + + + + + + + + + + + MM Pooled Staking + + + + + + + + + + + + + + + Network + + + + + + + + + + + + + Ethereum Main Network + + + + + + + + + + + + + + + Reward rate + + + + + + + + + + + + 2.8% + + + + + + + + + + + Estimated annual rewards + + + + + + + + + + $334.93 + + + 0.13 ETH + + + + + + + + + + + + Reward frequency + + + + + + + + + + + + 12 hours + + + + + + + + + + + + + Terms of service + + + + + Risk disclosure + + + + + + + Cancel + + + + + Confirm + + + + + +`; diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx index 1ca6560d7f4..0431e67a77f 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx @@ -50,8 +50,14 @@ const StakeInputView = () => { }; const handleStakePress = useCallback(() => { - // TODO: Display the Review bottom sheet: STAKE-824 - }, []); + navigation.navigate('StakeScreens', { + screen: Routes.STAKING.STAKE_CONFIRMATION, + params: { + amountWei: amountWei.toString(), + amountFiat: fiatAmount, + }, + }); + }, [amountWei, fiatAmount, navigation]); const balanceText = strings('stake.balance'); @@ -66,7 +72,11 @@ const StakeInputView = () => { : `${balanceFiatNumber?.toString()} ${currentCurrency.toUpperCase()}`; useEffect(() => { - navigation.setOptions(getStakingNavbar(title, navigation, theme.colors)); + navigation.setOptions( + getStakingNavbar(title, navigation, theme.colors, { + hasBackButton: false, + }), + ); }, [navigation, theme.colors, title]); useEffect(() => { diff --git a/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap b/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap index 5085ab0c15e..4a35aa2b83e 100644 --- a/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap +++ b/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap @@ -56,13 +56,9 @@ exports[`StakeInputView render matches snapshot 1`] = ` { "backgroundColor": "#ffffff", "borderBottomColor": "rgb(216, 216, 216)", - "elevation": 0, "flex": 1, - "shadowColor": "transparent", - "shadowOffset": { - "height": 0.5, - "width": 0, - }, + "shadowColor": "rgb(216, 216, 216)", + "shadowOffset": null, "shadowOpacity": 0.85, "shadowRadius": 0, } @@ -106,96 +102,26 @@ exports[`StakeInputView render matches snapshot 1`] = ` pointerEvents="box-none" style={ { - "alignItems": "flex-start", - "bottom": 0, - "justifyContent": "center", - "left": 0, - "opacity": 1, - "position": "absolute", - "top": 0, - } - } - > - - - - - - Stake ETH - - - - - Ethereum Main Network - - - + Stake ETH + { : strings('stake.review'); useEffect(() => { - navigation.setOptions(getStakingNavbar(title, navigation, theme.colors)); + navigation.setOptions( + getStakingNavbar(title, navigation, theme.colors, { + hasBackButton: false, + }), + ); }, [navigation, theme.colors, title]); const handleUnstakePress = useCallback(() => { diff --git a/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap b/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap index 15e289f23e7..5e7927b0b5c 100644 --- a/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap +++ b/app/components/UI/Stake/Views/UnstakeInputView/__snapshots__/UnstakeInputView.test.tsx.snap @@ -56,13 +56,9 @@ exports[`UnstakeInputView render matches snapshot 1`] = ` { "backgroundColor": "#ffffff", "borderBottomColor": "rgb(216, 216, 216)", - "elevation": 0, "flex": 1, - "shadowColor": "transparent", - "shadowOffset": { - "height": 0.5, - "width": 0, - }, + "shadowColor": "rgb(216, 216, 216)", + "shadowOffset": null, "shadowOpacity": 0.85, "shadowRadius": 0, } @@ -106,96 +102,26 @@ exports[`UnstakeInputView render matches snapshot 1`] = ` pointerEvents="box-none" style={ { - "alignItems": "flex-start", - "bottom": 0, - "justifyContent": "center", - "left": 0, - "opacity": 1, - "position": "absolute", - "top": 0, - } - } - > - - - - - - Unstake ETH - - - - - Ethereum Main Network - - - + Unstake ETH + jest.fn()); + +Image.getSize = jest.fn((_uri, success) => { + success(100, 100); // Mock successful response for ETH native Icon Image +}); const mockNavigate = jest.fn(); @@ -39,15 +29,17 @@ afterEach(() => { }); describe('StakingBalance', () => { + beforeEach(() => jest.resetAllMocks()); + it('render matches snapshot', () => { - render(StakingBalance); - expect(screen.toJSON()).toMatchSnapshot(); + const { toJSON } = renderWithProvider(); + expect(toJSON()).toMatchSnapshot(); }); it('redirects to StakeInputView on stake button click', () => { - render(StakingBalance); + const { getByText } = renderWithProvider(); - fireEvent.press(screen.getByText(strings('stake.stake_more'))); + fireEvent.press(getByText(strings('stake.stake_more'))); expect(mockNavigate).toHaveBeenCalledTimes(1); expect(mockNavigate).toHaveBeenCalledWith('StakeScreens', { @@ -56,9 +48,9 @@ describe('StakingBalance', () => { }); it('redirects to UnstakeInputView on unstake button click', () => { - render(StakingBalance); + const { getByText } = renderWithProvider(); - fireEvent.press(screen.getByText(strings('stake.unstake'))); + fireEvent.press(getByText(strings('stake.unstake'))); expect(mockNavigate).toHaveBeenCalledTimes(1); expect(mockNavigate).toHaveBeenCalledWith('StakeScreens', { diff --git a/app/components/UI/Stake/components/StakingBalance/StakingCta/StakingCta.tsx b/app/components/UI/Stake/components/StakingBalance/StakingCta/StakingCta.tsx index 1ab816b649d..13b3d2c8629 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingCta/StakingCta.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingCta/StakingCta.tsx @@ -36,10 +36,10 @@ const StakingCta = ({ estimatedRewardRate, style }: StakingCtaProps) => { {strings('stake.stake_your_eth_cta.base')} - {estimatedRewardRate} - - {strings('stake.stake_your_eth_cta.annually')} + + {estimatedRewardRate} + {strings('stake.stake_your_eth_cta.annually')}