React-native-fcm: TypeError: Cannot read property 'requestPermissions' of undefined

Created on 27 Feb 2017  ยท  7Comments  ยท  Source: evollu/react-native-fcm

"react": "^15.4.2",
"react-native": "^0.41.2",
"react-native-fcm": "^6.1.0",

When I run npm test, the following error comes up. I have no idea how to fix it because the project runs fine on both simulator and real device. The error only shows up during tests.

 FAIL  __tests__/index.ios.js
  โ— renders correctly

    TypeError: Cannot read property 'requestPermissions' of undefined

      at Object.<anonymous>.FCM.requestPermissions (node_modules/react-native-fcm/index.js:39:22)
      at App.componentDidMount (index.ios.js:19:26)
      at node_modules/react-test-renderer/lib/ReactCompositeComponent.js:265:25
      at measureLifeCyclePerf (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:75:12)
      at node_modules/react-test-renderer/lib/ReactCompositeComponent.js:264:11
      at CallbackQueue.notifyAll (node_modules/react-test-renderer/lib/CallbackQueue.js:76:22)
      at ReactTestReconcileTransaction.close (node_modules/react-test-renderer/lib/ReactTestReconcileTransaction.js:36:26)
      at ReactTestReconcileTransaction.closeAll (node_modules/react-test-renderer/lib/Transaction.js:206:25)
      at ReactTestReconcileTransaction.perform (node_modules/react-test-renderer/lib/Transaction.js:153:16)
      at batchedMountComponentIntoNode (node_modules/react-test-renderer/lib/ReactTestMount.js:69:27)

Here is my test file

import 'react-native';
import React from 'react';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
import Index from '../index.ios';

it('renders correctly', () => {
  renderer.create(
    <Index />,
  );
});

Here is my app delegate file

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNFIRMessaging.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"JDIFrontend"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  [FIRApp configure];
  [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
  return YES;
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
  [RNFIRMessaging willPresentNotification:notification withCompletionHandler:completionHandler];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
{
  [RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

//You can skip this method if you don't want to use local notification
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  [RNFIRMessaging didReceiveLocalNotification:notification];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
  [RNFIRMessaging didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

@end

Most helpful comment

Thanks for sharing! I ended up using the following mock function. You may need to mock more functions from react-native-fcm depending on which ones you used.

jest.mock('react-native-fcm', () =>({
  on: jest.fn(),
  requestPermissions: jest.fn(),
  getFCMToken: jest.fn(()=> new Promise((accept, resolve) => accept('FakeToken'))),
  FCMEvent: {
    Notification: 'fakeNotification',
  },
}));

All 7 comments

I too am getting the same error while running npm run test

Versions:

"react": "15.4.2",
"react-native": "^0.42.0-rc.3",
"react-native-fcm": "^6.0.3",

App runs fine on a real device, did not test on emulator due to testing notifications.

Was able to find a decent solution: http://stackoverflow.com/a/42142331

Thanks for sharing! I ended up using the following mock function. You may need to mock more functions from react-native-fcm depending on which ones you used.

jest.mock('react-native-fcm', () =>({
  on: jest.fn(),
  requestPermissions: jest.fn(),
  getFCMToken: jest.fn(()=> new Promise((accept, resolve) => accept('FakeToken'))),
  FCMEvent: {
    Notification: 'fakeNotification',
  },
}));

@fever324
I had something very similar but kept getting an error that it couldn't find Notification. In the end, I opted for that solution found on SO.

Glad we were both able to figure out a working solution. I'm pretty new to React Native, so I don't exactly know which style is preferred over the other for Testing.

Thanks

looks like issue is solved

@fever324 I have the same problem. In which file did you place your code for the mock function?

Ok this got me out of trouble. The above example didn't work. This is literally my first effort with Jest and it almost certainly not best practice, but I can now run my test.

Add a react-native-fcm.js file, in a__mocks__directory next to thenode_modules` directory in your app root.

So

<app>
    - node_modules
    - __mocks__
        - react-native-fcm.js

inside that file put the following code:

const fcm = jest.genMockFromModule('react-native-fcm');
fcm.default.getFCMToken =()=>new Promise((resolve, reject)=>{resolve()});
module.exports = fcm;

It seems you need to do a module.exports for it to work, and thats why the code in the previous comment wouldn't work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sf577 picture sf577  ยท  3Comments

havinhthai picture havinhthai  ยท  4Comments

Przemocny picture Przemocny  ยท  3Comments

holyxiaoxin picture holyxiaoxin  ยท  4Comments

Keksike picture Keksike  ยท  5Comments