Skip to content

Support "editable" on TextInput #476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thymikee opened this issue Jul 31, 2020 · 10 comments · Fixed by #517
Closed

Support "editable" on TextInput #476

thymikee opened this issue Jul 31, 2020 · 10 comments · Fixed by #517

Comments

@thymikee
Copy link
Member

Describe the Feature

TextInput component from react-native has its own handling of being disabled/editable. It's not using responder system like Views, Texts and thus Touchables, so the logic we have already fails to catch it.

We should consider adding custom handling specific to native TextInput component, since it was working with @testing-library/react-native before v7.

Possible Implementations

Will likely involve detecting TextInput and verify if it's editable or not.

Test that fails with current implementation:

test('should not fire on disabled TextInput', () => {
  const handleChangeText = jest.fn();

  const screen = render(
    <TextInput onChangeText={handleChangeText} editable={false}>
      <Text>Trigger</Text>
    </TextInput>
  );

  fireEvent.changeText(screen.getByText('Trigger'), 'Trigger');
  expect(handleChangeText).not.toHaveBeenCalled();
});
@pplytas
Copy link
Contributor

pplytas commented Aug 20, 2020

Hi @thymikee, I'd like to tackle this one.

@thymikee
Copy link
Member Author

@pitpitpat go for it!

@douglasjunior
Copy link

douglasjunior commented Aug 26, 2022

fireEvent(textInput, 'focus') still working when editable={false} 😢

I'm using version 11.0.0.

    const handleFocus = jest.fn();

    const result = render(
      <TextInput
        testID="my-input"
        onFocus={handleFocus}
        editable={false}
      />,
    );

    const rnTextInput = result.getByTestId('my-input');

    act(() => {
      fireEvent(rnTextInput, 'focus');
      // or fireEvent(rnTextInput, 'click');
      // or fireEvent.press(rnTextInput);
    });

    expect(handleFocus).not.toBeCalled();

Result:

image

@thymikee
Copy link
Member Author

@douglasjunior we have 2 tests for this scenario which are passing on our infra. Mind investigating on your side, reducing it to a minimal setup and see if some 3rd-party code doesn't interfere? Btw, there's no need to wrap fireEvent with act, it's done under the hood

@douglasjunior
Copy link

Hi @thymikee, thank you for the quick response!

I've just tested on a new project here.

Create a new RN 0.68.2 project using TypeScript template:

npx react-native init TestingLibrarySample --template [email protected]

Add testing-library:

yarn add -D @testing-library/react-native

Edit the __tests__/App-test.tsx to add:

  it('test TextInput native', () => {
    const handleFocus = jest.fn();

    const result = render(
      <TextInput testID="my-input" onFocus={handleFocus} editable={false} />,
    );

    const rnTextInput = result.getByTestId('my-input');

    fireEvent(rnTextInput, 'focus');

    expect(handleFocus).not.toBeCalled();
  });

Run tests:

yarn test

Sample project: https://github.com/douglasjunior/TestingLibrarySample

Other people with similar problem: https://stackoverflow.com/q/65625330/2826279

Thanks!

@thymikee
Copy link
Member Author

Would you be able to create a PR with this test failing?

@douglasjunior
Copy link

douglasjunior commented Aug 26, 2022

Would you be able to create a PR with this test failing?

Sure.


I think I figured out the problem, if using "placeholder" instead of "testID" works as expected.

  it('test TextInput native by placeholder', () => {
    const handleFocus = jest.fn();

    const result = render(
      <TextInput
        placeholder="my-input"
        onFocus={handleFocus}
        editable={false}
      />,
    );

    const rnTextInput = result.getByPlaceholderText('my-input');

    fireEvent(rnTextInput, 'focus');

    expect(handleFocus).not.toBeCalled(); // <--- pass
  });

  it('test TextInput native by testID', () => {
    const handleFocus = jest.fn();

    const result = render(
      <TextInput testID="my-input" onFocus={handleFocus} editable={false} />,
    );

    const rnTextInput = result.getByTestId('my-input');

    fireEvent(rnTextInput, 'focus');

    expect(handleFocus).not.toBeCalled(); // <--- fail
  });

@thymikee
Copy link
Member Author

Thanks! Looking forward to the PR :)

@douglasjunior
Copy link

Done #1080

@douglasjunior
Copy link

douglasjunior commented Aug 26, 2022

Another scenario that's don't work as expected is when wrapping with withTheme from @callstack/react-theme-provider, even using getByPlaceholderText:

  it('test TextInput native by custom component', () => {
    const CustomTextInput: React.FC<{ theme: AppThemeType } & TextInputProps> = props => <TextInput testID="rn-text-input" {...props} />;

    const CustomInputWithTheme = withTheme(CustomTextInput);

    const handleFocus = jest.fn();

    const result = render(
      <CustomInputWithTheme
        placeholder="my-input"
        onFocus={handleFocus}
        editable={false}
      />,
    );

    const rnTextInput = result.getByPlaceholderText('my-input');

    fireEvent(rnTextInput, 'focus');

    expect(handleFocus).not.toBeCalled(); // <--- fail
  });

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

Successfully merging a pull request may close this issue.

3 participants