Skip to content
This repository was archived by the owner on Jul 30, 2020. It is now read-only.

TypeError: require(...).configureNextLayoutAnimation is not a function. #26

Closed
lewie9021 opened this issue May 29, 2019 · 10 comments
Closed

Comments

@lewie9021
Copy link
Contributor

  • react-native or expo: react-native
  • native-testing-library version: 3.1.1
  • jest-preset: native-testing-library
  • react-native version: 0.59.2
  • node version: 10.13.0

Relevant code or config:

import * as React from "react";
import { Button, LayoutAnimation, Text, View } from "react-native";
import { fireEvent, render, waitForElement } from "native-testing-library";

function Example() {
  const [ showMessage, setShowMessage ] = React.useState(false);

  const toggleMessage = () => {
    LayoutAnimation.configureNext({
      ...LayoutAnimation.Presets.easeInEaseOut,
      duration: 100
    });

    setShowMessage((prevState) => !prevState);
  };

  return (
    <View>
      <Button
        testID="button"
        title="Print Username"
        onPress={toggleMessage}
      />
      {showMessage
        ? <Text testID="text">Hello World!</Text>
        : null
      }
    </View>
  );
}

test("component using LayoutAnimation works as expected", async () => {
  const { getByTestId, queryByTestId } = render(<Example />);

  const $button = getByTestId("button");
  fireEvent.press($button);

  const $text = await waitForElement(() => queryByTestId("text"));
  expect($text!.props.children).toEqual("Hello World!");
});

What you did:

Rendered a component that uses the LayoutAnimation API from the react-native package.

What happened:

I get the following exception:

TypeError: require(...).configureNextLayoutAnimation is not a function

       7 |
       8 |   const toggleMessage = () => {
    >  9 |     LayoutAnimation.configureNext({
         |                     ^
      10 |       ...LayoutAnimation.Presets.easeInEaseOut,
      11 |       duration: 100
      12 |     });

Reproduction:

See code snippet above.

Problem description:

Unless mocked manually, it's not possible to test component trees that use LayoutAnimation.

Suggested solution:

In my Jest setup script, I use the auto-mocking feature to simply mock the API surface of LayoutAnimation:

jest.mock("LayoutAnimation");

Is this something that could be mocked by this library automatically to avoid confusion for users in the future?

@bcarroll22
Copy link
Collaborator

Hey Lewis, I’ll leave this open for a bit to consider what to do.

The tricky part is if we go this route, the more mocking of native modules like this we do, the more reliant on maintaining our own jest preset we become. I know NativeAnimatedHelper is mocked in the preset right now, but honestly I didn’t even remember putting that in until I just looked while responding to this.

I’ve tried to leave the mocking of native modules up to the react native jest preset for the most part because that preset is very well maintained by the community. I guess I’m hesitant to commit to also mocking native modules as a part of this project. That said, let me think about it a little more, especially since it sounds like you’ve got a workable solution in the meantime 👍

@bcarroll22
Copy link
Collaborator

Alright @lewie9021 sorry it took so long to get back with you, I was thinking about what to do about this.

The thing about our jest preset is that it's very lightweight and should, in theory, work with pretty much any moderately recent version of React Native. That's because in theory, all the preset should do is mock the "native" components for ease of testing. I know this probably isn't the answer you were looking for, but I don't think I want to include these types of mocks in our preset because then it becomes hard to not just end up maintaining a potentially very complex jest preset separately from React Native's. The other huge downside is that it's unlikely that our preset would work with many versions of React Native other than the latest (possibly a few versions back, I suppose).

In cases like this, I think the best approach is to have your own setupAfterEnv file where you mock these types of native modules your project uses in a satisfactory way for your team, or mock it right in the file where you need to test it. Another very reasonable approach would be submitting a PR to React Native to add these mocks to their preset, they tend to be very responsive and quick about getting things merged.

Good luck, and thanks again!

@lewie9021
Copy link
Contributor Author

lewie9021 commented Jun 4, 2019

Thanks for taking the time to think about the correct approach for this problem.

I completely understand your hesitation to support mocking parts of React Native's public interface. You're absolutely right that if we support mocking here, it could land us in difficult situations when mocking other interfaces like this in the future - so it's best that we leave it to future versions of React Native to provide them.

Maybe it's worth a section in the documentation that covers these situations where the user might need to apply their own mocks? Even if React Native was to provide a full set of mocks in the future, users may still run into problems if they've integrated with custom native modules.

@bcarroll22
Copy link
Collaborator

I've actually not had to do this yet personally, would you like to make a pull request to the docs site? ☺️ I'd really appreciate it. I think this would be a really awesome thing to put in the recipes section! It can even just be a recap of your experience doing it as a starting point.

@lewie9021
Copy link
Contributor Author

It'll take me some time to prepare a PR, but I'll definitely try and submit something when I get chance :)

@bcarroll22
Copy link
Collaborator

See this comment: #27 (comment).

I’m going to go ahead and close this one too, because this is a specific symptom of a bigger problem. I’d like to see some collaboration to discuss how we can get a better mocked platform to use in tandem with this library. Thanks for your patience!

@ghost
Copy link

ghost commented Oct 1, 2019

In case anyone else runs into the same issue, here's how we got it to work:

jest.mock("react-native/Libraries/LayoutAnimation/LayoutAnimation", () => ({
  ...require.requireActual(
    "react-native/Libraries/LayoutAnimation/LayoutAnimation"
  ),
  configureNext: jest.fn(),
}));

For more context, here's the issue in react-native: facebook/react-native#26579

@acollazomayer
Copy link

@SophieDonut This solution did not work for me.

@AEgan
Copy link
Contributor

AEgan commented Dec 27, 2019

I used a similar solution to @SophieAu 's, maybe that'll work for you @acollazomayer

jest.mock('react-native', () => {
  const actualRN = require.requireActual('react-native');

  return Object.setPrototypeOf(
    {
      LayoutAnimation: {
        ...actualRN.LayoutAnimation,
        configureNext: jest.fn(),
      },
    },
    actualRN,
  );
});

@mzdon-ema
Copy link

In case anyone else looks at this... another solution that worked for us.

import { LayoutAnimation } from 'react-native';
...
jest.spyOn(LayoutAnimation, 'configureNext').mockImplementation(() => {});

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants