diff --git a/packages/mobile/jest_setup.ts b/packages/mobile/jest_setup.ts index 5c84b84ca1a..428e2b92f5e 100644 --- a/packages/mobile/jest_setup.ts +++ b/packages/mobile/jest_setup.ts @@ -20,3 +20,12 @@ afterEach(cleanup) // Mock LayoutAnimation as it's done not automatically jest.mock('react-native/Libraries/LayoutAnimation/LayoutAnimation.js') + +// Mock Animated Views this way otherwise we get a +// `JavaScript heap out of memory` error when a ref is set (?!) +// See https://github.com/callstack/react-native-testing-library/issues/539 +jest.mock('react-native/Libraries/Animated/src/components/AnimatedView.js', () => 'View') +jest.mock( + 'react-native/Libraries/Animated/src/components/AnimatedScrollView.js', + () => 'RCTScrollView' +) diff --git a/packages/mobile/src/account/__snapshots__/FiatExchange.test.tsx.snap b/packages/mobile/src/account/__snapshots__/FiatExchange.test.tsx.snap index d4e4ab62e3a..df31ade3928 100644 --- a/packages/mobile/src/account/__snapshots__/FiatExchange.test.tsx.snap +++ b/packages/mobile/src/account/__snapshots__/FiatExchange.test.tsx.snap @@ -41,14 +41,18 @@ exports[`FiatExchange renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/account/__snapshots__/GoldEducation.test.tsx.snap b/packages/mobile/src/account/__snapshots__/GoldEducation.test.tsx.snap index c9520c33e5d..061ffe00f61 100644 --- a/packages/mobile/src/account/__snapshots__/GoldEducation.test.tsx.snap +++ b/packages/mobile/src/account/__snapshots__/GoldEducation.test.tsx.snap @@ -45,14 +45,18 @@ exports[`renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/account/__snapshots__/Settings.test.tsx.snap b/packages/mobile/src/account/__snapshots__/Settings.test.tsx.snap index 47356152096..ac6244f1e45 100644 --- a/packages/mobile/src/account/__snapshots__/Settings.test.tsx.snap +++ b/packages/mobile/src/account/__snapshots__/Settings.test.tsx.snap @@ -40,14 +40,18 @@ exports[`Account renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -2297,14 +2301,18 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -3349,10 +3357,14 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - "width": 215, - } + Array [ + Object { + "width": 215, + }, + Object { + "opacity": 1, + }, + ] } > @@ -3417,9 +3432,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -3446,9 +3464,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -3475,9 +3496,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -3504,9 +3528,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -3533,9 +3560,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -3562,9 +3592,12 @@ exports[`Account renders correctly when dev mode active 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > @@ -4818,14 +4851,18 @@ exports[`Account renders correctly when verification is not possible 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/account/__snapshots__/Support.test.tsx.snap b/packages/mobile/src/account/__snapshots__/Support.test.tsx.snap index 0a9412cf871..c30a058175d 100644 --- a/packages/mobile/src/account/__snapshots__/Support.test.tsx.snap +++ b/packages/mobile/src/account/__snapshots__/Support.test.tsx.snap @@ -40,14 +40,18 @@ exports[`Support renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/alert/AlertBanner.tsx b/packages/mobile/src/alert/AlertBanner.tsx index 76bf5e0a1e6..feb6533feee 100644 --- a/packages/mobile/src/alert/AlertBanner.tsx +++ b/packages/mobile/src/alert/AlertBanner.tsx @@ -1,30 +1,37 @@ -import SmartTopAlert, { AlertTypes } from '@celo/react-components/components/SmartTopAlert' -import * as React from 'react' +import SmartTopAlert from '@celo/react-components/components/SmartTopAlert' +import React, { memo, useMemo } from 'react' import { useDispatch } from 'react-redux' import { hideAlert } from 'src/alert/actions' import { ErrorDisplayType } from 'src/alert/reducer' import useSelector from 'src/redux/useSelector' -export default function AlertBanner() { +function AlertBanner() { const alert = useSelector((state) => state.alert) const dispatch = useDispatch() - const onPress = () => { - const action = alert?.action ?? hideAlert() - dispatch(action) - } + const displayAlert = useMemo(() => { + if (alert?.displayMethod === ErrorDisplayType.BANNER && (alert.title || alert.message)) { + const onPress = () => { + const action = alert?.action ?? hideAlert() + dispatch(action) + } - return ( - - ) + const { type, title, message, buttonMessage, dismissAfter } = alert + + return { + type, + title, + message, + buttonMessage, + dismissAfter, + onPress, + } + } else { + return null + } + }, [alert]) + + return } + +export default memo(AlertBanner) diff --git a/packages/mobile/src/alert/__snapshots__/AlertBanner.test.tsx.snap b/packages/mobile/src/alert/__snapshots__/AlertBanner.test.tsx.snap index 07ab5fd4c9b..e16742dc38e 100644 --- a/packages/mobile/src/alert/__snapshots__/AlertBanner.test.tsx.snap +++ b/packages/mobile/src/alert/__snapshots__/AlertBanner.test.tsx.snap @@ -12,7 +12,6 @@ exports[`AlertBanner when an action is provided it dispatches the action when pr @@ -74,7 +79,6 @@ exports[`AlertBanner when error message passed in renders error message 1`] = ` @@ -174,7 +186,6 @@ exports[`AlertBanner when message and title passed in renders title with message @@ -257,7 +274,6 @@ exports[`AlertBanner when message passed in renders message 1`] = ` diff --git a/packages/mobile/src/backup/__snapshots__/BackupIntroduction.test.tsx.snap b/packages/mobile/src/backup/__snapshots__/BackupIntroduction.test.tsx.snap index b9692d38d9a..7447bfe0767 100644 --- a/packages/mobile/src/backup/__snapshots__/BackupIntroduction.test.tsx.snap +++ b/packages/mobile/src/backup/__snapshots__/BackupIntroduction.test.tsx.snap @@ -41,14 +41,18 @@ exports[`BackupIntroduction renders correctly when backup completed 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -245,14 +249,18 @@ exports[`BackupIntroduction renders correctly when backup not complete 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/exchange/__snapshots__/ExchangeHomeScreen.test.tsx.snap b/packages/mobile/src/exchange/__snapshots__/ExchangeHomeScreen.test.tsx.snap index 24a0fb946fe..14c2032beb0 100644 --- a/packages/mobile/src/exchange/__snapshots__/ExchangeHomeScreen.test.tsx.snap +++ b/packages/mobile/src/exchange/__snapshots__/ExchangeHomeScreen.test.tsx.snap @@ -46,14 +46,18 @@ exports[`ExchangeHomeScreen renders and behaves correctly for CP-DOTO restricted onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -130,332 +134,330 @@ exports[`ExchangeHomeScreen renders and behaves correctly for CP-DOTO restricted stickyHeaderIndices={Array []} testID="ExchangeScrollView" > - - + - - - goldPrice - - - - - - - - + goldPrice + - + - $10.00 - + + + - + + $10.00 + + + + + + - - - withdrawCelo - - + withdrawCelo + - + + + - + yourGoldBalance + + - yourGoldBalance + + + 2.000 - + - - - - 2.000 - - + } + > + Equal to - Equal to - - - $ - 26.60 - + + $ + 26.60 - - + + - + + - - global:activity - - - - + global:activity + + + `; @@ -506,14 +508,18 @@ exports[`ExchangeHomeScreen renders and behaves correctly for non CP-DOTO restri onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -590,507 +596,505 @@ exports[`ExchangeHomeScreen renders and behaves correctly for non CP-DOTO restri stickyHeaderIndices={Array []} testID="ExchangeScrollView" > - - + - - - goldPrice - - - - - - - - + goldPrice + - + - $10.00 - + + + - + + $10.00 + + + + + + - - - buy - - + buy + + + - - - sell - - + sell + - + + + - + yourGoldBalance + + - yourGoldBalance + + + 2.000 - + - - - - 2.000 - - + } + > + Equal to - Equal to - - - $ - 26.60 - + + $ + 26.60 - - + + + } + /> + - - - withdrawCelo - - - - + + + + - - - + /> + - + + - - global:activity - - - - + global:activity + + + `; diff --git a/packages/mobile/src/exchange/__snapshots__/ExchangeTradeScreen.test.tsx.snap b/packages/mobile/src/exchange/__snapshots__/ExchangeTradeScreen.test.tsx.snap index 74d41ae2183..1a9116a6acd 100644 --- a/packages/mobile/src/exchange/__snapshots__/ExchangeTradeScreen.test.tsx.snap +++ b/packages/mobile/src/exchange/__snapshots__/ExchangeTradeScreen.test.tsx.snap @@ -58,9 +58,12 @@ exports[`ExchangeTradeScreen renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } testID="ExchangeSwitchInput" > @@ -212,9 +215,12 @@ exports[`ExchangeTradeScreen renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } > diff --git a/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap b/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap index 94cf4e1e838..ff100f443c3 100644 --- a/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap +++ b/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap @@ -41,14 +41,18 @@ exports[`Testnet banner Renders when connected with backup complete 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -446,14 +450,18 @@ exports[`Testnet banner Renders when disconnected 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > @@ -851,14 +859,18 @@ exports[`Testnet banner Shows testnet banner for 5 seconds 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "left": 0, - "marginBottom": 0, - "marginLeft": 16, - "opacity": 1, - "padding": 0, - "position": "absolute", - } + Array [ + Object { + "left": 0, + "marginBottom": 0, + "marginLeft": 16, + "padding": 0, + "position": "absolute", + }, + Object { + "opacity": 1, + }, + ] } testID="Hamburguer" > diff --git a/packages/mobile/src/verify/VerificationLoadingScreen.test.tsx b/packages/mobile/src/verify/VerificationLoadingScreen.test.tsx index 933a3f67c82..71848d9268f 100644 --- a/packages/mobile/src/verify/VerificationLoadingScreen.test.tsx +++ b/packages/mobile/src/verify/VerificationLoadingScreen.test.tsx @@ -7,13 +7,6 @@ import VerificationLoadingScreen from 'src/verify/VerificationLoadingScreen' import { createMockStore } from 'test/utils' import { mockNavigation } from 'test/values' -// Mock AnimatedScrollView this way otherwise we get a -// `JavaScript heap out of memory` error when ref is set (?!) -jest.mock( - 'react-native/Libraries/Animated/src/components/AnimatedScrollView.js', - () => 'RCTScrollView' -) - // Lock time so snapshots always show the same countdown value jest.spyOn(Date, 'now').mockImplementation(() => 1487076708000) diff --git a/packages/mobile/src/verify/__snapshots__/VerificationLoadingScreen.test.tsx.snap b/packages/mobile/src/verify/__snapshots__/VerificationLoadingScreen.test.tsx.snap index deefa623f79..2018ff72255 100644 --- a/packages/mobile/src/verify/__snapshots__/VerificationLoadingScreen.test.tsx.snap +++ b/packages/mobile/src/verify/__snapshots__/VerificationLoadingScreen.test.tsx.snap @@ -244,11 +244,15 @@ exports[`VerificationLoadingScreen renders correctly 1`] = ` { it('renders correctly', async () => { const { toJSON } = render( ) diff --git a/packages/react-components/components/SmartTopAlert.tsx b/packages/react-components/components/SmartTopAlert.tsx index 3ed95cb6077..4f5bfbdc244 100644 --- a/packages/react-components/components/SmartTopAlert.tsx +++ b/packages/react-components/components/SmartTopAlert.tsx @@ -2,65 +2,26 @@ import SmallButton from '@celo/react-components/components/SmallButton' import Error from '@celo/react-components/icons/Error' import colors from '@celo/react-components/styles/colors' import fontStyles from '@celo/react-components/styles/fonts' -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { Animated, FlexStyle, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' - -export enum AlertTypes { - MESSAGE = 'message', - ERROR = 'error', -} - -interface AlertProps { - title?: string | null - text: string | null - onPress: () => void - type: AlertTypes - dismissAfter?: number | null - buttonMessage?: string | null -} - -interface Props extends AlertProps { - isVisible: boolean - timestamp: number +interface Props { + alert: { + type: 'message' | 'error' + title?: string | null + message: string + dismissAfter?: number | null + buttonMessage?: string | null + onPress: () => void + } | null } // This component needs to be always mounted for the hide animation to be visible -function SmartTopAlert(props: Props) { - const [visibleAlertState, setVisibleAlertState] = useState(null) +function SmartTopAlert({ alert }: Props) { + const [visibleAlertState, setVisibleAlertState] = useState(alert) const insets = useSafeAreaInsets() const yOffset = useRef(new Animated.Value(-500)) const containerRef = useRef() - const animatedRef = useCallback((node) => { - containerRef.current = node && node.getNode() - }, []) - - const alertState = useMemo(() => { - // tslint bug? - // tslint:disable-next-line: no-shadowed-variable - const { isVisible, type, title, text, buttonMessage, dismissAfter, onPress } = props - if (isVisible) { - return { - type, - title, - text, - buttonMessage, - dismissAfter, - onPress, - } - } else { - return null - } - }, [ - props.timestamp, - props.isVisible, - props.type, - props.title, - props.text, - props.buttonMessage, - props.dismissAfter, - props.onPress, - ]) function hide() { if (!containerRef.current) { @@ -81,14 +42,14 @@ function SmartTopAlert(props: Props) { } useEffect(() => { - if (alertState) { + if (alert) { // show - setVisibleAlertState(alertState) + setVisibleAlertState(alert) } else { // hide hide() } - }, [alertState]) + }, [alert]) useEffect(() => { let rafHandle: number @@ -132,8 +93,8 @@ function SmartTopAlert(props: Props) { return null } - const { type, title, text, buttonMessage, onPress } = visibleAlertState - const isError = type === AlertTypes.ERROR + const { type, title, message, buttonMessage, onPress } = visibleAlertState + const isError = type === 'error' const testID = isError ? 'errorBanner' : 'infoBanner' @@ -141,7 +102,7 @@ function SmartTopAlert(props: Props) { } {!!title && {title} } - {text} + {message} {buttonMessage && ( diff --git a/packages/react-components/components/__snapshots__/TextInputWithButtons.test.tsx.snap b/packages/react-components/components/__snapshots__/TextInputWithButtons.test.tsx.snap index 4b8da0fd475..95bb6fcce0e 100644 --- a/packages/react-components/components/__snapshots__/TextInputWithButtons.test.tsx.snap +++ b/packages/react-components/components/__snapshots__/TextInputWithButtons.test.tsx.snap @@ -46,9 +46,12 @@ exports[`TextInputWithButtons renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - Object { - "opacity": 1, - } + Array [ + undefined, + Object { + "opacity": 1, + }, + ] } testID="Touchable" > diff --git a/packages/react-components/jest_setup.js b/packages/react-components/jest_setup.js index 00465bc93ca..7a5320d75c9 100644 --- a/packages/react-components/jest_setup.js +++ b/packages/react-components/jest_setup.js @@ -16,3 +16,12 @@ if (typeof window !== 'object') { global.window = global global.window.navigator = {} } + +// Mock Animated Views this way otherwise we get a +// `JavaScript heap out of memory` error when a ref is set (?!) +// See https://github.com/callstack/react-native-testing-library/issues/539 +jest.mock('react-native/Libraries/Animated/src/components/AnimatedView.js', () => 'View') +jest.mock( + 'react-native/Libraries/Animated/src/components/AnimatedScrollView.js', + () => 'RCTScrollView' +)