RNPickerSelect unit testing (changing the value)

Viewed 1074

I'm using this library for select/options and I'd like to unit test certain things like if there's the disabled passed to it, prevent it from changing the value. So far, I tried something like this:
Component:

import React, {useState, useEffect} from 'react';
import {View} from 'react-native';
import RNPickerSelect from 'react-native-picker-select';

export default function PickerInput(props) {
    const [pickerItems, setPickerItems] = useState([]);
    const [selectedIndex, setSelectedIndex] = useState(0);
    const [placeholder, setPlaceholder] = useState({});
    const [error, setError] = useState(false);
    const [enabled, setEnabled] = useState(true);

    useEffect(() => {
        // loop over options prop and construct the array
        const pickerItemsArray = [];
        if (
            Array.isArray(props.options) &&
            props.options.length &&
            props.selectedIndex >= 0
        ) {
            props.options.map((option, index) => {
                pickerItemsArray.push({
                    label: option,
                    value: index,
                });
            });
        }

        // push the constructed array
        {
            pickerItemsArray.length
                ? setPickerItems(pickerItemsArray)
                : setPickerItems([]);
        }

        // check if placeholder prop has a value and pass it, else pass empty object to prevent the picker from showing a placeholder
        {
            props.placeholder &&
                setPlaceholder({
                    label: props.placeholder,
                    value: null,
                });
        }

        {
            setError(props.error);
        }

        {
            !props.enabled ? setEnabled(false) : setEnabled(true);
        }
    }, []);

    useEffect(() => {
        props.selectedIndex < 0 && setSelectedIndex(-1);

        // check if selectedIndex prop is larger than the options prop and set it to the length of options prop, else pass the selectedIndex prop
        {
            Array.isArray(props.options) &&
            props.options.length - 1 < props.selectedIndex &&
            props.selectedIndex >= 0
                ? setSelectedIndex(props.options.length - 1)
                : setSelectedIndex(props.selectedIndex);
        }
    }, [selectedIndex]);

    const onValueChange = value => {
        if ((value === 0 || value) && props.enabled) {
            setSelectedIndex(value);
            props.onValueChange(pickerItems[value].label);
        } else {
            setSelectedIndex(null);
        }
    };

    return (
        <View
            testID="picker-wrapper">
            <RNPickerSelect
                onValueChange={value => onValueChange(value)}
                items={pickerItems}
                disabled={!enabled}
                placeholder={placeholder}
                value={selectedIndex}
            />
        </View>
    );
}

Test:

...
it('should not make the component change value when enabled is false', () => {
    const props = {
        placeholder: 'Select',
        options: ['testOption', 'testOption2'],
        selectedIndex: 0,
        error: false,
        enabled: false,
    };

    const newSelectedIndex = 1;

    const {queryByTestId} = render(
        <PickerInput {...props} onValueChange={true} />,
    );

    const pickerWrapper = queryByTestId('picker-wrapper');

        pickerWrapper.props.children.props.value = newSelectedIndex

    expect(pickerWrapper.props.children.props.value).toBe(
        props.selectedIndex,
    );
});

I'm pretty new to react native and also testing, is this the best way to achieve this? Shouldn't there be a fireEvent where I fire the event of changing the value? I can't seem to find any. Would really appreciate someone's help.

1 Answers

First, you can add a touchableWrapperProps prop to your RNPickerSelect component in order to add a testID like this:

<RNPickerSelect
  touchableWrapperProps={{testID: 'picker-select'}}
  ...
/>

(Found from this issue here)

Then, you can fire the onValueChange event in your test like so to change the value.

fireEvent(getTestId('picker-select'), 'onValueChange', '1');
Related