meliorence / react-native-snap-carousel

Swiper/carousel component for React Native featuring previews, multiple layouts, parallax images, performant handling of huge numbers of items, and more. Compatible with Android & iOS.
BSD 3-Clause "New" or "Revised" License
10.36k stars 2.29k forks source link

PrettyFormatPluginError: Invalid string lengthRangeError when snapshotting Carousel #849

Open leonie-koch opened 3 years ago

leonie-koch commented 3 years ago

Is this a bug report, a feature request, or a question?

bug

Have you followed the required steps before opening a bug report?

(Check the step you've followed - put an x character between the square brackets ([]).)

Have you made sure that it wasn't a React Native bug?

Yes

Is the bug specific to iOS or Android? Or can it be reproduced on both platforms?

Not platform specific

Is the bug reproductible in a production environment (not a debug one)?

Only debug mode

Environment

Environment: React: 17.0.1 React native: 0.64.0 react-native-snap-carousel: ^3.9.1

Expected Behavior

I'd like to make jest snapshots of my carousel UI.

Actual Behavior

I am getting the following error:

PrettyFormatPluginError: Invalid string lengthRangeError: Invalid string length

      at printObjectProperties (node_modules/pretty-format/build/collections.js:172:47)
      at printComplexValue (node_modules/pretty-format/build/index.js:295:48)
      at printer (node_modules/pretty-format/build/index.js:378:10)
      at printObjectProperties (node_modules/pretty-format/build/collections.js:171:21)
      at printComplexValue (node_modules/pretty-format/build/index.js:295:48)
      at printer (node_modules/pretty-format/build/index.js:378:10)
      at printObjectProperties (node_modules/pretty-format/build/collections.js:171:21)
      at printComplexValue (node_modules/pretty-format/build/index.js:295:48)
      at printer (node_modules/pretty-format/build/index.js:378:10)
      at printObjectProperties (node_modules/pretty-format/build/collections.js:171:21)

If I mock react-native-snap-carousel the test passes (currently commented in code). Here is my test file:

/**
 * @format
 */

import 'react-native';
import React from 'react';
import {Tutorial1} from '../screens/Tutorial1';
import * as eva from '@eva-design/eva';
import {EvaIconsPack} from '@ui-kitten/eva-icons';
import {ApplicationProvider, IconRegistry} from '@ui-kitten/components';
import renderer from 'react-test-renderer';
jest.useFakeTimers();
jest.mock('@react-navigation/native');
// jest.mock('react-native-snap-carousel');

it('renders correctly', () => {
  const tree = renderer
    .create(
      <>
        <IconRegistry icons={EvaIconsPack} />
        <ApplicationProvider {...eva} theme={eva.light}>
          <Tutorial1 />
        </ApplicationProvider>
      </>,
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

And my component:

import React, {useState, useRef, useEffect, useCallback} from 'react';
import {SafeAreaView, StyleSheet, View, Dimensions} from 'react-native';
import {
  Button,
  Divider,
  Icon,
  Layout,
  TopNavigation,
  TopNavigationAction,
  Text,
} from '@ui-kitten/components';
import Carousel, {ParallaxImage} from 'react-native-snap-carousel';

const GLOBAL = require('./components/constants');

export const Tutorial1 = ({navigation}) => {
  const BackIcon = props => <Icon {...props} name="chevron-left-outline" />;
  const [activeIndex, setActiveIndex] = useState(0);
  const [carouselItems, setCarouselItems] = useState(GLOBAL.CAROUSEL_ITEMS);
  const ref = useRef(null);
  const window = Dimensions.get('window');
  const CARD_WIDTH = window.width * 0.8;
  const CAROUSEL_WIDTH = window.width;
  const [isFirst, setIsFirst] = useState(false);
  const [isLast, setIsLast] = useState(false);

  const navigateBack = () => {
    navigation.goBack();
  };

  const goForward = () => {
    ref.current.snapToNext();
  };

  const goBack = () => {
    ref.current.snapToPrev();
  };

  const BackAction = () => (
    <TopNavigationAction icon={BackIcon} onPress={navigateBack} />
  );

  const renderItem = useCallback(({item, index}, parallaxProps) => {
    return (
      <View style={styles.intro_item}>
        <ParallaxImage
          source={item.thumbnail}
          containerStyle={styles.item_image_container}
          style={styles.item_image}
          parallaxFactor={0.4}
          {...parallaxProps}
        />
        <Text style={styles.item_text} category="h6">
          {item.title}
        </Text>
        <Text style={styles.item_text}>{item.text}</Text>
      </View>
    );
  }, []);

  useEffect(() => {
    console.log(activeIndex);
    if (activeIndex == 0) {
      setIsFirst(true);
    } else if (activeIndex == 2) {
      setIsLast(true);
    } else {
      setIsFirst(false);
      setIsLast(false);
    }
  }, [activeIndex]);

  return (
    <SafeAreaView style={{flex: 1}}>
      <TopNavigation
        title="Intro"
        alignment="center"
        accessoryLeft={BackAction}
      />
      <Divider />
      <Layout style={styles.container} level="4">
        <Layout style={styles.intro} level="4">
          <Carousel
            layout={'default'}
            ref={ref}
            data={carouselItems}
            renderItem={renderItem}
            onSnapToItem={index => setActiveIndex(index)}
            sliderWidth={CAROUSEL_WIDTH}
            itemWidth={CARD_WIDTH}
            windowSize={1}
            hasParallaxImages={true}
            testID="carousel"
          />
        </Layout>

        <Layout style={styles.intro_bottom} level="4">
          {isFirst ? (
            <Button
              style={styles.intro_button}
              onPress={goBack}
              disabled={true}>
              Zurück
            </Button>
          ) : (
            <Button style={styles.intro_button} onPress={goBack}>
              Zurück
            </Button>
          )}

          {isLast ? (
            <Button
              style={styles.intro_button}
              onPress={() => navigation.navigate('Optionen wählen')}>
              Starten
            </Button>
          ) : (
            <Button style={styles.intro_button} onPress={goForward}>
              Weiter
            </Button>
          )}
        </Layout>
        <Layout style={styles.skip} level="4">
          <Text
            style={styles.skip_text}
            onPress={() => navigation.navigate('Optionen wählen')}>
            Überspringen
          </Text>
        </Layout>
      </Layout>
    </SafeAreaView>
  );
};

Steps to Reproduce

(Write your steps so that anyone can reproduce the issue in the Snack demo you provided.)

  1. create react native app
  2. added code above
  3. ran npm test
palania-fl commented 3 years ago

Do we have any fix?

this happening only when adding the below lines

loop={true} loopClonesPerSide={containerItem.resources && containerItem.resources.length}

brambang commented 3 years ago

same issue, it occur with our 1 device test.

dohooo commented 3 years ago

@l30ni3 Sorry, please allow me to advertise for my open source library! ~ I think this library react-native-reanimated-carousel will solve your problem. It is a high performance and very simple component, complete with React-Native reanimated 2