Partially mock `react-native` module - react-native

I'm running unit tests in React Native that need the NativeEventEmitter and NativeModules mocked but leave everything else as passthrough to the real code.
This part seems to be working except when running I get this error.
Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'DevSettings' could not be found. Verify that a module by this name is registered in the native binary.
at invariant (../node_modules/invariant/invariant.js:40:15)
at Object.getEnforcing (../node_modules/react-native/Libraries/TurboModule/TurboModuleRegistry.js:39:3)
at Object.<anonymous> (../node_modules/react-native/Libraries/NativeModules/specs/NativeDevSettings.js:30:37)
at Object.<anonymous> (../node_modules/react-native/Libraries/Utilities/DevSettings.js:10:1)
Mocking:
jest.mock(
'react-native',
() => ({
...jest.requireActual('react-native'),
NativeEventEmitter: class MockNativeEventEmitter {
// ...
},
NativeModules: {
// ...
},
Platform: {
OS: 'android',
},
})
);
Online searches for this error all point to problems compiling in dev vs release mode, nothing remotely close to what I'm trying to do.

Have you tried importing DevSettings from react-native and adding the same imported module in your mock? This would be the process for every Component/Module being used in your tested component. Something like:
import { DevSettings } from 'react-native`
jest.mock(
'react-native',
() => ({
...jest.requireActual('react-native'),
NativeEventEmitter: class MockNativeEventEmitter {
// ...
},
NativeModules: {
// ...
},
Platform: {
OS: 'android',
},
DevSettings
})
);

Related

Testing Angular 14 Standalone Components with Spectator

Our test runner is Jest.
Our component is marked as standalone: true,
If try to set up spectator like this:
describe('OurComponent', () => {
let spectator: Spectator<OurComponent>;
const fakeActivatedRoute: ActivatedRoute = {
snapshot: {data: {}},
} as ActivatedRoute;
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
imports: [
// some imports
],
providers: [
// some providers
],
detectChanges: false,
shallow: true,
});
beforeEach(async () => {
spectator = componentFactory();
});
it('should be created', () => {
expect(spectator).toBeDefined();
});
});
Then we run into the following error:
"Error: Unexpected "OurComponent" found in the "declarations" array of the "TestBed.configureTestingModule" call, "OurComponent" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?"
Using the Angular-CLI in order to generate resulted in a component with a test file which is built upon ComponentFixture.
How can we make it possible to test a standalone component using Spectator?
Depends on your spectator version (mine is 10.0.0) but you can use the declareComponent property :
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
declareComponent: false,
});

getting error after upgrading to expo sdk 44 to 46

I have upgraded my expo application which was expo sdk 44 to expo sdk 46.
After upgrading I got this error and trying to figure this for last 4 days. Any help would be helpful..
Here is the error:
ERROR Invariant Violation: ViewPropTypes has been removed from React Native. Migrate to ViewPropTypes exported from 'deprecated-react-native-prop-types'.
Invariant Violation: "main" has not been registered. This can happen if:
* Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.
* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:95:4 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:141:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo/build/errors/ExpoErrorManager.js:25:19 in errorHandler
at node_modules/expo/build/errors/ExpoErrorManager.js:30:24 in <anonymous>
at node_modules/#react-native/polyfills/error-guard.js:49:36 in ErrorUtils.reportFatalError
Steps I followed:
Upgraded Expo SDK into 45 and compiled successfully and then upgraded again into SDK 46
Tried registerRootComponent from a file named main.js refernece from expo
Also tried this answer which refers the multiple copies of react-native-safe-area-context tried this solution also
Fixed this issue:
Step 1:
Install the plugin
yarn add --dev babel-plugin-module-resolver deprecated-react-native-prop-types
Step 2:
create index.js file inside project folder resolver/react-native/ with following code
import * as StandardModule from 'react-native';
const deprecatedProps = {
ImagePropTypes: require('deprecated-react-native-prop-types/DeprecatedImagePropType'),
TextPropTypes: require('deprecated-react-native-prop-types/DeprecatedTextPropTypes'),
ViewPropTypes: require('deprecated-react-native-prop-types/DeprecatedViewPropTypes'),
ColorPropType: require('deprecated-react-native-prop-types/DeprecatedColorPropType'),
EdgeInsetsPropType: require('deprecated-react-native-prop-types/DeprecatedEdgeInsetsPropType'),
PointPropType: require('deprecated-react-native-prop-types/DeprecatedPointPropType'),
};
const imgProx = new Proxy(StandardModule.Image, {
get(obj, prop) {
if (prop === 'propTypes') return deprecatedProps.ImagePropTypes;
return Reflect.get(...arguments);
},
});
const txtProx = new Proxy(StandardModule.Text, {
get(obj, prop) {
if (prop === 'propTypes') return deprecatedProps.TextPropTypes;
return Reflect.get(...arguments);
},
});
// Had to use a proxy because ...StandardModule made think react-native that all modules were
// being used and was triggering some unnecessary validations / native dep checks.
// This prevents that from happening.
const objProx = new Proxy(StandardModule, {
get(obj, prop) {
if (prop in deprecatedProps) {
return deprecatedProps[prop];
}
if (prop === 'Image') {
return imgProx;
}
if (prop === 'Text') {
return txtProx;
}
return Reflect.get(...arguments);
},
});
module.exports = objProx;
Step 3:
configure module resolver inside babel.config.js, depends on your project requirement to blacklist/whitelist certain npm packages to prevent conflicting file.
example module-resolver config :
var path = require('path');
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
["module-resolver", {
"root": ["."],
resolvePath(sourcePath, currentFile, opts) {
if (
sourcePath === 'react-native' &&
!(
(
currentFile.includes('node_modules/react-native/') || // macos/linux paths
currentFile.includes('node_modules\\react-native\\')
) // windows path
) &&
!(
currentFile.includes('resolver/react-native/') ||
currentFile.includes('resolver\\react-native\\')
)
) {
return path.resolve(__dirname, 'resolver/react-native');
}
/**
* The `opts` argument is the options object that is passed through the Babel config.
* opts = {
* extensions: [".js"],
* resolvePath: ...,
* }
*/
return undefined;
}
}],
],
};
for reference this guide

Unexpected string error in Jest with './environment/validate.fx';

In my React Native app, I'm just starting to write a test file, which runs fine like this:
// #flow
import type {
Location,
LocationAction
} from "../src/redux/reducers/locationReducer";
// import { getLocationSaga } from "../src/redux/actions/locationActions";
import SagaTester from "redux-saga-tester";
import recordSaga from "../recordSaga";
describe("getLocationAsync", () => {
const calculatedSimulatorLocation: Location = {
latitude: 37.33233141,
latitudeDelta: 0.0004491555874955085,
longitude: -122.0312186,
longitudeDelta: -0.05737702242408729
};
const startAction: LocationAction = { type: "USER_LOCATION_START" };
const successAction: LocationAction = {
type: "USER_LOCATION_SUCCESS",
region: calculatedSimulatorLocation
};
describe("userLocationSaga", () => {
it("gets the user's location", async () => {
const dispatched = await recordSaga(getLocationSaga, startAction);
expect(dispatched).toContainEqual(successAction);
});
});
});
The test, of course, fails because getLocationSaga is not defined. I've stubbed the function in my actions file:
// #flow
import { Location } from "expo";
import type { LocationAction } from "../reducers/locationReducer";
import type { Saga } from "redux-saga";
export function getLocationAsync(): LocationAction {
return { type: "USER_LOCATION_START" };
}
export function* getLocationSaga(): Saga<void> {
return console.log("hello from saga");
}
But when I uncomment the line in the tests that imports this method, I get this error:
● Test suite failed to run
/Users/TuzMacbookPro2017/Development/QMG-local/APPS/QMGTrago/node_modules/expo/build/Expo.fx.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import './environment/validate.fx';
^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Unexpected string
at ScriptTransformer._transformAndBuildScript (node_modules/#jest/transform/build/ScriptTransformer.js:471:17)
at ScriptTransformer.transform (node_modules/#jest/transform/build/ScriptTransformer.js:513:25)
at Object.<anonymous> (node_modules/expo/src/Expo.ts:1:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 7.506s
Ran all test suites.
Watch Usage: Press w to show more.
How do I fix this? Below are some config files:
package.json
...
"jest": {
"preset": "react-native"
},
...
.eslintrc
{
"parser": "babel-eslint",
"extends": "airbnb",
"plugins": ["react", "jsx-ally", "import"]
}
babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ["babel-preset-expo", "#babel/preset-flow"]
};
};
I had this same issue today on a react-native/ expo app that is using jest. I referenced their guide at https://docs.expo.io/versions/latest/guides/testing-with-jest/. I looked at the following section listing the transform patterns to ignore:
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|#react-native-community|expo(nent)?|#expo(nent)?/.*|react-navigation|#react-navigation/.*|#unimodules/.*|sentry-expo|native-base)"
]
This is found in jest config file (mine is jest.config.js). I noticed mine was missing the following: |#unimodules/.*|sentry-expo|expo(nent)?|#expo(nent)?/.*|
I included those to fix that specific error.
However, I then got the following errors :
The Expo SDK requires Expo to run. It appears the native Expo modules are unavailable and this code is not running on Expo.
I discovered that I needed to configure my jest to work with jest-expo according to the docs.

Background-Fetch: Cannot read property 'configure' of Undefined

I have been trying to integrate the transistorsoft background-fetch library without success:
https://github.com/transistorsoft/react-native-background-fetch
When I chain any method to the BackgroundFetch component I get the error (attached in this post)
import BackgroundFetch from "react-native-background-fetch";
class TimerScreen extends React.Component {
...
componentDidMount() {
this.configureBackgroundFetch();
}
...
configureBackgroundFetch() {
// Configure BackgroundFetch.
BackgroundFetch.configure({
minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
stopOnTerminate: false, // <-- Android-only,
startOnBoot: true, // <-- Android-only
enableHeadless: true
}, async () => {
console.log('BackgroundFetch has started');
BackgroundFetch.finish(BackgroundFetch.FETCH_RESULT_NEW_DATA);
}, (error) => {
console.log('RNBackgroundFetch failed to start')
});
}
...
I haven't been able to find out why the library isn't working. I have used react native link and installed it in package.json
...
{
...
"react-native-background-fetch": "^2.5.3",
...
}
...
The problem was caused by Expokit not being configured correctly to use native modules. I made a bare React Native app and the library worked without returning an error.

Difference between import and require in jest

I am writing my first test for a react-native project using react-native-router-flux and react-redux
My code is something like
jest.autoMockOff();
jest.setMock('react-native', {
NativeModules: {}
});
jest.setMock('react-native-router-flux', {
Actions: {}
});
const mockStore = require('../../mock/Store');
const actions = require('../myActions');
...
// Some tests that test if the right actions are dispatched.
The above works, However when I use ES6 import instead of require I have a problem.
If I replace
const actions = require('../myActions');
with
import * as actions from "../myActions"
I get the below error.
Runtime Error
- Error: Cannot find module 'ReactNative' from 'react-native.js'
at Resolver.resolveModule (node_modules/jest-cli/node_modules/jest-resolve/src/index.js:117:17)
at Object.<anonymous> (node_modules/react-native/Libraries/react-native/react-native.js:175:25)
at Object.<anonymous> (node_modules/react-native-router-flux/src/Scene.js:10:18)
While I can work with this, I am curious to understand the reason for failure,
Also note that I am just not able to transpile react-native-router-flux with es2015 presets in .bablerc file and I think I will have to live with that limitation (of not being able to transpile react-native-router-flux).
myActions.js looks like
import {Actions} from 'react-native-router-flux';
export function searchRequest() {
return {
type: "search_request"
}
}
export function searchRequestFailure(error) {
return {
type: "search_request_failure",
error: error.toString()
}
}
export function searchRequestSuccess(payload) {
return {
type: "search_request_success",
payload: payload
}
}
export function search(nameOrAddress) {
return dispatch => {
dispatch(searchRequest())
return fetch("http://localhost:8080/search", {
method: "GET"
}).then((response) => {
return response.json()
}).then((responseData) => {
dispatch(searchRequestSuccess(responseData))
Actions.list() //react-native-router-flux dependency
}).catch(error => {
dispatch(searchRequestFailure(error))
})
}
}
Using react-native 0.26 and jest 12.1.1
That is not the correct ES6 conversion.
const actions = require('../myActions'); // requires the defaultMember of the exported module and
//ES6 (ES2015) equivalent is
import actions from '../myActions';
https://developer.mozilla.org/en/docs/web/javascript/reference/statements/import