react-native-reanimated icon indicating copy to clipboard operation
react-native-reanimated copied to clipboard

TypeError: expect.extend is not a function

Open billnbell opened this issue 2 years ago • 19 comments

Latest RN 2.8.0 "react-native-reanimated": "2.8.0".

Getting: FAIL src/tests/ComponentRender-test.tsx ● Test suite failed to run

TypeError: expect.extend is not a function

  at Object.setUpTests (node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js:219:10)
  at Object.<anonymous> (jestSetupFile.js:163:62)

billnbell avatar May 05 '22 15:05 billnbell

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snippet of code, a snack or a link to a GitHub repository that reproduces the problem?

github-actions[bot] avatar May 05 '22 15:05 github-actions[bot]

Hey! 👋

It looks like you've omitted a few important sections from the issue template.

Please complete Description, Snack or minimal code example, Package versions and Affected platforms sections.

github-actions[bot] avatar May 05 '22 15:05 github-actions[bot]

This happens on jest upgrade from ^27.5.1 → ^28.0.3

billnbell avatar May 05 '22 15:05 billnbell

To fix this:

  1. Ensure you are calling this inside a script script that runs in setupFilesAfterEnv NOT setupFiles
  2. Change the import in the script to const { expect } = require('@jest/globals'); from const expect = require('expect'); with patch-package

I have opened a PR to fix this here: #3217

matt-oakes avatar May 06 '22 09:05 matt-oakes

To fix this:

  1. Ensure you are calling this inside a script script that runs in setupFilesAfterEnv NOT setupFiles
  2. Change the import in the script to const { expect } = require('@jest/globals'); from const expect = require('expect'); with patch-package

I have opened a PR to fix this here: #3217

i've tried the same thing you did, but it still shows me the same error

finalight avatar May 24 '22 08:05 finalight

To fix this:

  1. Ensure you are calling this inside a script script that runs in setupFilesAfterEnv NOT setupFiles
  2. Change the import in the script to const { expect } = require('@jest/globals'); from const expect = require('expect'); with patch-package

I have opened a PR to fix this here: #3217

same error, i believe this resolve this error when merge, link do helper: https://jestjs.io/pt-BR/docs/upgrading-to-jest28

mayconline avatar May 26 '22 01:05 mayconline

the PR is merged, but i still facing the same error

  ● Test suite failed to run

    TypeError: expect.extend is not a function

      22 | }
      23 |
    > 24 | require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests()
         |                                                              ^
      25 |
      26 | // eslint-disable-next-line no-underscore-dangle
      27 | global.__reanimatedWorkletInit = jest.fn()

      at Object.extend [as setUpTests] (node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js:152:12)
      at Object.setUpTests (jest-utils/jest.setup.js:24:62)

finalight avatar Aug 18 '22 07:08 finalight

@matt-oakes
Here is a repo showing how it breaks after upgrading to jest 28 https://github.com/Norfeldt/expo-46-with-jest-rtnl-reanimated

When I try to run it in my private repo with jest ~26 it blows up:

yarn run v1.22.19
$ jest --config='./test/jest/config.js' --colors --coverage=false --forceExit --runInBand
watchman warning:  Recrawled this watch 257 times, most recently because:
MustScanSubDirs UserDroppedTo resolve, please review the information on
https://facebook.github.io/watchman/docs/troubleshooting.html#recrawl
To clear this warning, run:
...

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

      at Object.get findNodeHandle [as findNodeHandle] (node_modules/react-native/index.js:196:12)
      at AnimatedComponent._detachPropUpdater (node_modules/react-native-reanimated/lib/createAnimatedComponent.js:490:40)
      at AnimatedComponent.componentWillUnmount (node_modules/react-native-reanimated/lib/createAnimatedComponent.js:243:14)
      at callComponentWillUnmountWithTimer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12755:14)
      at safelyCallComponentWillUnmount (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12762:5)

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

      15 |       {props.children}
      16 |     </TouchableWithoutFeedback>
    > 17 |   )
         |    ^
      18 | }
      19 |

      at Object.get TouchableWithoutFeedback [as TouchableWithoutFeedback] (node_modules/react-native/index.js:126:12)
      at DismissKeyboard (components/DismissKeyboard/index.tsx:17:44)
      at describeNativeComponentFrame (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2031:7)
      at describeFunctionComponentFrame (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2126:12)
      at describeFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2783:14)

  ●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "The above error occurred in the <AnimatedComponent(Text)> component:

        at AnimatedComponent (/Users/norfeldt/repos/NORD.investments/expo-app/node_modules/react-native-reanimated/lib/createAnimatedComponent.js:150:36)
        at Moti (/Users/norfeldt/repos/NORD.investments/expo-app/node_modules/@motify/core/lib/commonjs/motify.tsx:55:9)
        

Norfeldt avatar Aug 25 '22 07:08 Norfeldt

still erroring!!!!!!

billnbell avatar Aug 25 '22 19:08 billnbell

It's not missing a repo. I provided a minimal example repro that reproduce the issue.

Norfeldt avatar Aug 26 '22 14:08 Norfeldt

pretty simple repo. I just added require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests(); in the setup-tests.js and it fails with expect.extend is not a function

 FAIL  src/components/member/explore/destination-screen/__tests__/helpers.test.ts
  ● Test suite failed to run

    TypeError: expect.extend is not a function

      1 | import 'react-native';
      2 |
    > 3 | require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests();
        |                                                              ^
      4 |

      at Object.extend [as setUpTests] (node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js:160:12)
      at Object.setUpTests (setup-tests.js:3:62)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:16)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:25:9)

billnbell avatar Aug 29 '22 03:08 billnbell

The try/catch is around the wrong things. The fix is:

Go into node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js

export const setUpTests = (userConfig = {}) => {
    require('setimmediate');
    frameTime = Math.round(1000 / config.fps);
    config = Object.assign(Object.assign({}, config), userConfig);
    let expect;
    try {
        expect = require('expect');
        expect.extend({
            toHaveAnimatedStyle(received, expectedStyle, config = {}) {
                return compareStyle(received, expectedStyle, config);
            },
        });
    }
    catch (_) {
        // for Jest in version 28+
        const { expect: expectModule } = require('@jest/globals');
        expect = expectModule;
        expect.extend({
            toHaveAnimatedStyle(received, expectedStyle, config = {}) {
                return compareStyle(received, expectedStyle, config);
            },
        });
    }
};

billnbell avatar Aug 29 '22 03:08 billnbell

Patch file

diff --git a/node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js b/node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js
index d8befd8..9e41d37 100644
--- a/node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js
+++ b/node_modules/react-native-reanimated/lib/reanimated2/jestUtils.js
@@ -145,23 +145,28 @@ export const advanceAnimationByFrame = (count) => {
     jest.advanceTimersByTime(frameTime);
 };
 export const setUpTests = (userConfig = {}) => {
+    require('setimmediate');
+    frameTime = Math.round(1000 / config.fps);
+    config = Object.assign(Object.assign({}, config), userConfig);
     let expect;
     try {
         expect = require('expect');
+        expect.extend({
+            toHaveAnimatedStyle(received, expectedStyle, config = {}) {
+                return compareStyle(received, expectedStyle, config);
+            },
+        });
     }
     catch (_) {
         // for Jest in version 28+
         const { expect: expectModule } = require('@jest/globals');
         expect = expectModule;
+        expect.extend({
+            toHaveAnimatedStyle(received, expectedStyle, config = {}) {
+                return compareStyle(received, expectedStyle, config);
+            },
+        });
     }
-    require('setimmediate');
-    frameTime = Math.round(1000 / config.fps);
-    config = Object.assign(Object.assign({}, config), userConfig);
-    expect.extend({
-        toHaveAnimatedStyle(received, expectedStyle, config = {}) {
-            return compareStyle(received, expectedStyle, config);
-        },
-    });
 };
 export const getAnimatedStyle = (received) => {
     return getCurrentStyle(received);

billnbell avatar Aug 29 '22 03:08 billnbell

Also, for RV 0.69+hermes has moved to c++17 and it needs to be modified:

s.xcconfig               = {
    "CLANG_CXX_LANGUAGE_STANDARD" => "c++14",
    "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/glog\" \"$(PODS_ROOT)/#{folly_prefix}Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\"",
                               "OTHER_CFLAGS" => "$(inherited)" + " " + folly_flags  }

Change to:

s.xcconfig               = {
    "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
    "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/glog\" \"$(PODS_ROOT)/#{folly_prefix}Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\"",
                               "OTHER_CFLAGS" => "$(inherited)" + " " + folly_flags  }

billnbell avatar Aug 29 '22 03:08 billnbell

@billnbell thank you very much for sharing your fix for the issue 🙌 (will try it later this week)

@billnbell github-actions seems to think that there still are missing a repo - does it have to be you that add it? If so you can perhaps fork mine or link to it?

Norfeldt avatar Aug 29 '22 13:08 Norfeldt

@billnbell is it too much to ask if you could make a PR to show the fix to the demo repo I have provided?

Norfeldt avatar Sep 07 '22 17:09 Norfeldt

Here's the fix https://github.com/software-mansion/react-native-reanimated/pull/3559

yusufyildirim avatar Sep 10 '22 12:09 yusufyildirim

This does not require a repo. Install React Native 0.70 and create a simple jest test, and it blows up.

The fixes provided above work well.

billnbell avatar Sep 10 '22 18:09 billnbell

@yusufyildirim

Here's the fix #3559

Tried to open the PR, copy the content from the file changed into the my node_modules/react-native-reanimated2 and do a yarn patch-package react-native-reanimated - did not work. Then I took the suggestion from @billnbell https://github.com/software-mansion/react-native-reanimated/issues/3215#issuecomment-1229705286 and replaced the content in the patch to that. Now it seems to get pass the expect extend error.

There still seems to be some issues regarding "now"

TextField › input field › has accessibility label and hint for the input field

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

      at Object.now (node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js:14:72)
      at JSReanimated.now [as getTimestamp] (node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js:25:34)
      at Timeout.getTimestamp [as _onTimeout] (node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js:32:37)
Screenshot 2022-09-14 at 15 10 12
<PATH>/expo-app/node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js:54
          return global.ReanimatedDataMock.now();
                                           ^

TypeError: Cannot read properties of undefined (reading 'now')
    at Object.now (<PATH>/expo-app/node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js:14:72)

Norfeldt avatar Sep 14 '22 13:09 Norfeldt

Fwiw, I had to use the following, but it is working for me now:

  1. Use @billnbell code: https://github.com/software-mansion/react-native-reanimated/issues/3215#issuecomment-1229703463
  2. Run npx patch-package react-native-reanimated
  3. This failed because the patch was too big. So I had to temporarily bump up patch-packages maxBuffer which I found here: https://github.com/ds300/patch-package/issues/166#issuecomment-591934894, note this fix is already in place, so I had bump it up even more using maxBuffer: 1024 * 1024 * 100 * 100
  4. This comment keyed me into making sure my config was updated for Jest 28+ from react-native-reanimated. Basically make sure your Jest setup for react-native-reanimated is up to date.
  5. At this point I was good, but then I still needed to commit the files, which I couldn't do because the patch was too big. For that you can use Git Large File Storage (which I'm still setting up).

imjamescrain avatar Oct 12 '22 15:10 imjamescrain

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

github-actions[bot] avatar Oct 12 '22 15:10 github-actions[bot]

@Norfeldt

I fixed the now() TypeErrors by changing node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js line 14. Inside the constructor within the if (isJest()) statement

before

this.timeProvider = { now: () => global.ReanimatedDataMock.now() };

after

this.timeProvider = { now: () => global.performance.now() };

Not sure if this is the right way to go or if it actually fixes the issue, but I'm not getting any more TypeErrors at least.

bmarden avatar Oct 12 '22 23:10 bmarden

@Norfeldt

I fixed the now() TypeErrors by changing node_modules/react-native-reanimated/lib/reanimated2/js-reanimated/JSReanimated.js line 14. Inside the constructor within the if (isJest()) statement

before

this.timeProvider = { now: () => global.ReanimatedDataMock.now() };

after

this.timeProvider = { now: () => global.performance.now() };

Not sure if this is the right way to go or if it actually fixes the issue, but I'm not getting any more TypeErrors at least.

not work for me

Youssef-Durgham avatar Oct 19 '22 21:10 Youssef-Durgham

any one fix this error ?

Youssef-Durgham avatar Oct 19 '22 21:10 Youssef-Durgham

fixed by doing that expo start -c
will fix your error

Youssef-Durgham avatar Oct 19 '22 22:10 Youssef-Durgham

Closing since fix is already merged: https://github.com/software-mansion/react-native-reanimated/pull/3559

Latropos avatar Aug 04 '23 10:08 Latropos