From e956f9912e9b5e6980fb25c501bbb8a9cfb28001 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Tue, 7 Jul 2020 14:57:31 -0700 Subject: [PATCH] jest: Mock `react-native` ourselves. The immediate need is to set up a way to mock the new `ZLPConstants` in `NativeModules`, which we'll do in an upcoming commit. Doing this, as recommended by React Native [1], also means we're better prepared for the React Native v0.61 upgrade (#3781), in which Haste is removed [2]. A consequence of that removal, it seems, is that mocks like this one, which we have now: ``` jest.mock('Linking', () => { ... }` ``` , won't work. Several people have handled this by changing 'Linking' to something like 'react-native/Libraries/Linking/Linking', but this is brittle because it couples our tests with the current directory structure in 'react-native'. Better to do it this way. We considered following the advice of others at that issue, including a blog post [3] responding to the official suggestion with an alternative. But we didn't reproduce the problems the post's author mentioned, and we've so far been able to explain the hiccups we've seen. [1] https://github.com/facebook/react-native/issues/26579#issuecomment-535244001 [2] https://github.com/facebook/react-native/issues/26579#issuecomment-535765528 [3] https://github.com/facebook/react-native/issues/26579#issuecomment-578409111 --- jest/jestSetup.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/jest/jestSetup.js b/jest/jestSetup.js index 97f1a29db41..7e84faae72a 100644 --- a/jest/jestSetup.js +++ b/jest/jestSetup.js @@ -1,4 +1,46 @@ import mockAsyncStorage from '@react-native-community/async-storage/jest/async-storage-mock'; +import * as ReactNative from 'react-native'; + +// Following upstream advice [1], mock `react-native` ourselves. +// +// Helpful in particular for adding to NativeModules, to simulate +// modules being available after the bridge initializes. +// +// The 'react-native' we import here is already mocked to a great +// extent by `node_modules/react-native-jest/setup.js`, thanks to our +// having declared `preset: 'react-native'` in our Jest config. +// +// For how we fall back on these already-mocked properties: +// +// Following the suggested implementation, we don't do something like +// an object spread, but instead set the returned object's prototype +// to be ReactNative. They don't explain why, but at least one reason +// seems to be to avoid triggering deprecation warnings on accessing, +// e.g., ReactNative.CameraRoll, which would would be done during a +// spread as each property is enumerated. +// +// [1] https://github.com/facebook/react-native/issues/26579#issuecomment-535244001 + +jest.mock('react-native', () => + // Extend ReactNative + Object.setPrototypeOf( + { + // We don't mock anything in these two, but + // `react-native-vector-icons` uses an odd indirection: they + // have a `lib/react-native.js` file with just the following: + // + // `export * from 'react-native';` + // + // This seems to mean that the ReactNative prototype (which + // we're setting to be the prototype of the object created by + // this literal) is ignored. So, put these directly in the + // object literal. + Platform: ReactNative.Platform, + StyleSheet: ReactNative.StyleSheet, + }, + ReactNative, + ), +); jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);