React-native: Cannot test WebView - Cannot read property 'decelerationRate' of undefined

Created on 17 Feb 2017  路  15Comments  路  Source: facebook/react-native

Description

I updated from react-native 0.39 to 0.41.2.
Now, WebView tests fail.

Reproduction

My example is more complicated (I shallow render a component containing a WebView) but I can reproduce it with the following snippet:

import React from 'react';
import { shallow } from 'enzyme'
import { WebView } from 'react-native';

describe('Test', () => {
    it('test', () => {
        shallow(<WebView />);
    });
});
TypeError: Cannot read property 'decelerationRate' of undefined

      at Object.<anonymous> (node_modules\react-native\Libraries\Components\WebView\WebView.ios.js:541:3254)
      at Object.get WebView [as WebView] (node_modules\react-native\Libraries\react-native\react-native.js:69:22)
      at Object.<anonymous> 

I'm sure it's not an enzyme bug as I can reproduce it with 'react-test-renderer' as well.

Solution

?

Additional Information

  • React Native version: 0.41.2 (React: 15.4.2)
  • Platform: neither
  • Operating System: At least Windows and CentOS
Locked

Most helpful comment

I was able to get around the error by calling jest.unmock('ScrollView') before my test

It has something to do with Jest automatically mocking ScrollView, which WebView needs to validate propTypes in WebView.ios.js:
decelerationRate: ScrollView.propTypes.decelerationRate,

I'm still getting a console.error of Warning: Stateless function components cannot be given refs (See ref "webview" in StatelessComponent created by WebView). Attempts to access this ref will fail. even though my component is not stateless, but my tests are passing.

All 15 comments

cc @cpojer

I was able to get around the error by calling jest.unmock('ScrollView') before my test

It has something to do with Jest automatically mocking ScrollView, which WebView needs to validate propTypes in WebView.ios.js:
decelerationRate: ScrollView.propTypes.decelerationRate,

I'm still getting a console.error of Warning: Stateless function components cannot be given refs (See ref "webview" in StatelessComponent created by WebView). Attempts to access this ref will fail. even though my component is not stateless, but my tests are passing.

I encounter the same problem with jest and storyshots.

Just want to add that this still occurs in 0.42 and also affects MacOS.

Same problem here. The component is not even stateless

+1

I am getting this error as well, specifically:

Warning: Stateless function components cannot be given refs (See ref "webview" in StatelessComponent created by WebView). Attempts to access this ref will fail.

I wonder if this should be opened in a separate issue as the title doesn't reflect this particular problem.

Suggestion on a possible fix.

Currently inside of WebView.ios.js and WebView.android.js the RCTWebView component is setting its ref like this:

<RCTWebView
    ref={RCT_WEBVIEW_REF}

where that constant is set like this

var RCT_WEBVIEW_REF = 'webview';

If however we set the ref with something like this:

<RCTWebView
    ref={(wv) => { this.webview = wv }}

and of course change the reference to this in getWebViewHandle from

getWebViewHandle = (): any => {
    return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
};

to

getWebViewHandle = (): any => {
    return ReactNative.findNodeHandle(this.webview);
};

the Warning I mentioned above seems to go away.

ReactCompositeComponent is where this check

component._compositeType !== CompositeTypes.StatelessFunctional

is being made while attaching the refs in attachRef, which is causing the warning message we are seeing.

I'm still a little fuzzy on why this component is considered a StatelessFunctional component because it doesn't appear to be.

Have you tried jest.mock('WebView', () => 'WebView')? That worked for us.

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@benkraus jest.mock('WebView', () => 'WebView') worked in general, but doesn't work in the case where you're actually testing WebView functions. I could simulate events (through sinon & enzyme), but would miss picking up the renderLoad function call. @computerjazz's jest.unmock('ScrollView') did the trick for me and got me to 100% coverage for testing elements with a WebView.

this should be reopend because the bug is still there

@awreese Have you had success spying on the onLoad callbacks? I am trying to, but it seems that the test finished before the webview actually renders so my spies are never called.

@sfratini Yes, I believe so... I used Sinon for spying, and Enzyme for test rendering components... something along the lines of...

in componentWithWebView

<WebView
  ... other event props
  onLoad={(e) => componentWithWebView.handleEvent(e)} // *** event handler ***
  ... other props
/>

in component test

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

import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';

Enzyme.configure({ adapter: new Adapter() });

import componentWithWebView from '...';  // *** import component with webview being tested ***

jest.unmock('scrollView'); // *** view note above for this ***

describe('Component with WebView test', () => {

  ... other tests

  describe('Event Handlers handle events', () => {
    let handleEventSpy;
    let wrapper;
    beforeAll(() => {
      handleEventSpy = sinon.spy(componentWithWebView, 'handleEvent');
      wrapper = shallow(<componentWithWebView/>);
    });

    beforeEach(() => {
      handleEventSpy.reset();
    });

    ... other event tests

    it('Load event handled', () => {
      const event = {
        nativeEvent: {
          url: "test",
        }
      };

      expect(handleEventSpy.called).toBe(false);
      wrapper.simulate('Load', event);
      expect(handleEventSpy.calledOnce).toBe(true);
    });

    ... other event tests
  }

  ... other tests

}

Does this help you?

Thanks, yes! So you are doing the same as me, where you manually simulate the onLoad, instead of actually leaving the WebView load the URL.

Was this page helpful?
0 / 5 - 0 ratings