GeekyAnts / NativeBase

Mobile-first, accessible components for React Native & Web to build consistent UI across Android, iOS and Web.
https://nativebase.io/
MIT License
20.21k stars 2.39k forks source link

A warning thrown with jest #5371

Open tmhao2005 opened 2 years ago

tmhao2005 commented 2 years ago

Description

There was a warning thrown as we ran test as following: TypeError: _reactNative.AppState.removeEventListener is not a function

CodeSandbox/Snack link

https://codesandbox.io/s/codesandbox-sse-example-forked-izm8zv?file=/sample.test.jsx

Steps to reproduce

  1. Visit the above codesanbox
  2. Run yarn test command then you will the see the warning

NativeBase Version

3.4.15

Platform

Other Platform

No response

Additional Information

No response

ahilles107 commented 2 years ago

my stack trace for this issue

    console.error
      Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.

      Error message:

      TypeError: _reactNative.AppState.removeEventListener is not a function
          at HybridProvider (/Users/xxx/node_modules/native-base/lib/commonjs/core/hybrid-overlay/HybridProvider.tsx:9:3)
          at ResponsiveQueryProvider (/Users/xxx/node_modules/native-base/lib/commonjs/utils/useResponsiveQuery/ResponsiveQueryProvider.tsx:20:12)
          at RNCSafeAreaProvider
          at Component (/Users/xxx/node_modules/react-native/jest/mockNativeComponent.js:17:18)
          at SafeAreaProvider (/Users/xxx/node_modules/react-native-safe-area-context/lib/commonjs/SafeAreaContext.tsx:35:3)
          at Provider (/Users/xxx/node_modules/native-base/lib/commonjs/utils/createContext.tsx:9:13)
          at NativeBaseProvider (/Users/xxx/node_modules/native-base/lib/commonjs/core/NativeBaseProvider.tsx:52:5)
          at TestingNativeBaseProvider (/Users/xxx/tests/ui/TestingNativeBaseProvider.tsx:5:3)
devpgcs commented 2 years ago

Same issue when updating from version^3.4.12 to ^3.4.16.

ankit-tailor commented 2 years ago

Hey everyone, Thanks for reporting the issue. We'll fix it.

MateuszRostkowski commented 2 years ago

Hey guys, I've created temporary patch for this issue:

File: /patches/native-base+3.4.16.patch

diff --git a/node_modules/native-base/lib/commonjs/core/color-mode/hooks.js b/node_modules/native-base/lib/commonjs/core/color-mode/hooks.js
index 8e28efe..68490c8 100644
--- a/node_modules/native-base/lib/commonjs/core/color-mode/hooks.js
+++ b/node_modules/native-base/lib/commonjs/core/color-mode/hooks.js
@@ -45,9 +45,9 @@ const useAppState = () => {
   const subscription = _react.default.useMemo(() => ({
     getCurrentValue: () => _reactNative.AppState.currentState,
     subscribe: callback => {
-      _reactNative.AppState.addEventListener('change', callback);
+      const sb = _reactNative.AppState.addEventListener('change', callback);

-      return () => _reactNative.AppState.removeEventListener('change', callback);
+      return () => sb.remove()
     }
   }), []);

After next release, just delete this patch.

am2619015 commented 2 years ago

Any idea on witch version this fix will be introduced? The new version native-base 3.4.18 still dont fix this bug

Still getting this warning:

Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.

Error message:

TypeError: _reactNative.AppState.removeEventListener is not a function
    in HybridProvider (created by NativeBaseProvider)
    in ResponsiveQueryProvider (created by NativeBaseProvider)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by NativeBaseProvider)
    in NativeBaseConfigProviderProvider (created by NativeBaseProvider)
    in NativeBaseProvider (created by CameraView)
    in CameraView (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SceneView)
    in RCTView (created by View)
    in View (created by DebugContainer)
    in DebugContainer (created by MaybeNestedStack)
    in MaybeNestedStack (created by SceneView)
    in RNSScreen (created by AnimatedComponent)
    in AnimatedComponent
    in AnimatedComponentWrapper (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by SceneView)
    in SceneView (created by NativeStackViewInner)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by ScreenStack)
austinrbrown01 commented 2 years ago

Getting the same error here when running tests with Jest

`console.error Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.

Error message:

TypeError: _reactNative.AppState.removeEventListener is not a function
    at children (\node_modules\native-base\lib\commonjs\core\hybrid-overlay\HybridProvider.tsx:9:3)
    at disableCSSMediaQueries (node_modules\native-base\lib\commonjs\utils\useResponsiveQuery\ResponsiveQueryProvider.tsx:20:12)
    at RNCSafeAreaProvider
    at RNCSafeAreaProvider (node_modules\react-native\jest\mockNativeComponent.js:17:18)
    at children (node_modules\react-native-safe-area-context\lib\commonjs\SafeAreaContext.tsx:35:3)
    at children (\node_modules\native-base\lib\commonjs\utils\createContext.tsx:9:13)
    at colorModeManager (\node_modules\native-base\lib\commonjs\core\NativeBaseProvider.tsx:52:5)`
maaliHasan commented 1 year ago

I'm using native-base version 3.4.19 and still have the issue! Any updates on this?

bebe84 commented 1 year ago

Yes, got the same error, please fix it 🙏

Update:

After updating to "native-base": "^3.4.25", jest no longer throws this error 👍

dhcmega commented 1 year ago

Hi The problem is still there but it has moved to a different file? Using 3.4.25

%s%s, TypeError: react_native_1.Dimensions.removeEventListener is not a function. (In 'react_native_1.Dimensions.removeEventListener('change', onChange)', 'react_native_1.Dimensions.removeEventListener' is undefined), in CheckinScreen (created by Screens)

node_modules/native-base/src/utils/useResponsiveQuery/common.ts

// The below implementation is taken from React Native's source and added a flag to conditionally attach/remove listeners
export const useDimensionsWithEnable = ({ enable }: { enable?: boolean }) => {
  const [dimensions, setDimensions] = React.useState(() =>
    Dimensions.get('window')
  );

  React.useEffect(() => {
    if (enable) {
      function handleChange({ window }: { window: ScaledSize }) {
        if (
          dimensions.width !== window.width ||
          dimensions.height !== window.height ||
          dimensions.scale !== window.scale ||
          dimensions.fontScale !== window.fontScale
        ) {
          setDimensions(window);
        }
      }
      Dimensions.addEventListener('change', handleChange);
      // We might have missed an update between calling `get` in render and
      // `addEventListener` in this handler, so we set it here. If there was
      // no change, React will filter out this update as a no-op.
      handleChange({ window: Dimensions.get('window') });

      return () => {
        Dimensions.removeEventListener('change', handleChange);  //  <- HERE! ####################
      };
    }
    return () => {};
  }, [dimensions, enable]);
  return dimensions;
};
r3dm1ke commented 1 year ago

Version 3.4.28 still has this bug:

 console.error
    Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committ
ing an already-finished tree, or an inconsistent return pointer.

    Error message:

    TypeError: Cannot read properties of undefined (reading 'remove')
        at HybridProvider (C:\personal_projects\clean-gta-clients\node_modules\native-base\lib\commonjs\core\hybrid-overlay\HybridProvider.tsx:9:3)
        at ResponsiveQueryProvider (C:\personal_projects\clean-gta-clients\node_modules\native-base\lib\commonjs\utils\useResponsiveQuery\ResponsiveQueryProvider.tsx:20:12)
        at RNCSafeAreaProvider
        at Component (C:\personal_projects\clean-gta-clients\node_modules\react-native\jest\mockNativeComponent.js:17:18)
        at SafeAreaProvider (C:\personal_projects\clean-gta-clients\node_modules\react-native-safe-area-context\src\SafeAreaContext.tsx:35:3)
        at Provider (C:\personal_projects\clean-gta-clients\node_modules\native-base\lib\commonjs\utils\createContext.tsx:9:13)
        at NativeBaseProvider (C:\personal_projects\clean-gta-clients\node_modules\native-base\lib\commonjs\core\NativeBaseProvider.tsx:52:5)
joaosousafranco commented 1 year ago

Same here but with the badge component, im doing the following:

const TestComponent = (props: Record<string, unknown>) => <View {...props} />

jest.mock('native-base', () => ({
  ...jest.requireActual('native-base'),
  HamburgerIcon: () => <TestComponent testID="menu-icon" />,
  AddIcon: () => <TestComponent testID="add-icon" />,
}))

the error:

TypeError: Cannot read properties of undefined (reading 'Badge')

       7 | const TestComponent = (props: Record<string, unknown>) => <View {...props} />
       8 |
    >  9 | jest.mock('native-base', () => ({
         |                          ^
      10 |   ...jest.requireActual('native-base'),
      11 |   HamburgerIcon: () => <TestComponent testID="menu-icon" />,
      12 |   AddIcon: () => <TestComponent testID="add-icon" />,

      at Object.get [as Badge] (node_modules/native-base/lib/commonjs/index.js:95:24)
          at Function.assign (<anonymous>)
      at assign (app/test/ui/pages/HomePage/components/Header.test.tsx:9:26)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/primitives/Hidden/HiddenSSR.tsx:2:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/primitives/Hidden/index.tsx:9:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/primitives/index.ts:69:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/composites/Alert/AlertIcon.tsx:2:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/composites/Alert/index.tsx:1:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/components/composites/index.ts:13:1)
      at Object.<anonymous> (node_modules/native-base/lib/commonjs/index.tsx:1:1)
ammanvedi commented 11 months ago

Came across this and same issue as @joaosousafranco

jest.mock('native-base', () => {
  console.log(jest.requireActual('native-base'))
  return {
    ...jest.requireActual('native-base'),
    Collapse: (props: ICollapseProps) => {
      if (props.isOpen) {
        props.onAnimationEnd?.()
      }
      return props.isOpen ? props.children : null
    },
  }
})
TypeError: Cannot read properties of undefined (reading 'Badge')
unpunnyfuns commented 8 months ago

This solved the last two issues for me, from https://stackoverflow.com/a/70174052:

jest.requireActual inside of jest.mock seems like the way to go, however I needed to add a proxy instead of the object spread to prevent the type error Cannot read properties of undefined (reading ...) which can occur in certain import scenarios. This is the final result:

jest.mock('the-module-to-mock', () => {
  const actualModule = jest.requireActual('the-module-to-mock')

  return new Proxy(actualModule, {
    get: (target, property) => {
      switch (property) {
        // add cases for exports you want to mock
        // 👇👇👇
        case 'foo': {
          return jest.fn() // add `mockImplementation` etc
        }
        case 'bar': {
          return jest.fn()
        }
        // fallback to the original module
        default: {
          return target[property]
        }
      }
    },
  })
})