Skip to content
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

TouchableWithoutFeedback Component doesn't disable click functionality when disabled #30953

Closed
amarlette opened this issue Feb 10, 2021 · 12 comments
Labels
Accessibility Component: TouchableWithoutFeedback Good first issue Interested in collaborating? Take a stab at fixing one of these issues. Platform: Android Android applications. Resolution: Locked This issue was locked by the bot.

Comments

@amarlette
Copy link

amarlette commented Feb 10, 2021

Description

When using a screen reader the TouchableWithoutFeedback component doesn't disable click functionality.

This issue is covered in-depth by parent issue #30840, please check there for more details.

React Native version:

0.63

@saurabhkacholiya
Copy link

Hi, @amarlette I am new to opensource can I pick up this issue?

@amarlette
Copy link
Author

Yes you can! I would recommend checking out our contribution guide (https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to help get you started.

@saurabhkacholiya
Copy link

I have tested TouchableWithoutFeedback is working fine this commit Here solve the issue

@amarlette
Copy link
Author

@saurabhkacholiya can you attach the test that you used to confirm this?

@fabOnReact
Copy link
Contributor

I have tested TouchableWithoutFeedback is working fine this commit Here solve the issue

I would say no

function Pressable(props: Props, forwardedRef): React.Node {

const accessibilityState =
disabled != null
? {...props.accessibilityState, disabled}
: props.accessibilityState;

those changes are in the Pressable component and I could not find any usage of Pressable in TouchableWithoutFeedback.
This makes sense as TouchableWithoutFeedback was built before Pressable, but I don't know well those .js libraries...
Tomorrow I will further investigate and try to add the props in

accessible: this.props.accessible !== false,

☮️ 🙏

@saurabhkacholiya
Copy link

@amarlette I am adding snapshots and test cases please validate.
Test Cases

describe('<TouchableWithoutFeedback />', () => {
  it('should render as expected', () => {
    const instance = ReactTestRenderer.create(
      <TouchableWithoutFeedback>
        <Text>Touchable</Text>
      </TouchableWithoutFeedback>,
    );

    expect(instance.toJSON()).toMatchSnapshot();
  });
});

describe('<TouchableWithoutFeedback disabled={true} />', () => {
  it('should be disabled when disabled is true', () => {
    const instance = ReactTestRenderer.create(
      <TouchableWithoutFeedback disabled={true}>
        <Text>Touchable</Text>
      </TouchableWithoutFeedback>,
    );
    expect(instance.toJSON()).toMatchSnapshot();
  });
});

describe('<TouchableWithoutFeedback disabled={true} accessibilityState={{}} />', () => {
  it('should be disabled when disabled is true and accessibilityState is empty', () => {
    const instance = ReactTestRenderer.create(
      <TouchableWithoutFeedback disabled={true} accessibilityState={{}}>
        <Text>Touchable</Text>
      </TouchableWithoutFeedback>,
    );
    expect(instance.toJSON()).toMatchSnapshot();
  });
});

describe('<TouchableWithoutFeedback disabled={true} accessibilityState={{checked: true}} />', () => {
  it('should keep accessibilityState when disabled is true', () => {
    const instance = ReactTestRenderer.create(
      <TouchableWithoutFeedback
        disabled={true}
        accessibilityState={{checked: true}}>
        <Text>Touchable</Text>
      </TouchableWithoutFeedback>,
    );
    expect(instance.toJSON()).toMatchSnapshot();
  });
});

describe('<TouchableWithoutFeedback disabled={true} accessibilityState={{disabled: false}} />', () => {
  it('should overwrite accessibilityState with value of disabled prop', () => {
    const instance = ReactTestRenderer.create(
      <TouchableWithoutFeedback
        disabled={true}
        accessibilityState={{disabled: false}}>
        <Text>Touchable</Text>
      </TouchableWithoutFeedback>,
    );
    expect(instance.toJSON()).toMatchSnapshot();
  });
});

SnapShot

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<TouchableWithoutFeedback /> should render as expected 1`] = `
<Text
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback /> should render as expected: should deep render when mocked (please verify output manually) 1`] = `
<Text
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback /> should render as expected: should deep render when not mocked (please verify output manually) 1`] = `
<Text
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback /> should render as expected: should shallow render as <TouchableWithoutFeedback /> when mocked 1`] = `
<TouchableWithoutFeedback>
  <Text>
    Touchable
  </Text>
</TouchableWithoutFeedback>
`;

exports[`<TouchableWithoutFeedback /> should render as expected: should shallow render as <TouchableWithoutFeedback /> when not mocked 1`] = `
<TouchableWithoutFeedback>
  <Text>
    Touchable
  </Text>
</TouchableWithoutFeedback>
`;

exports[`<TouchableWithoutFeedback disabled={true} /> should be disabled when disabled is true 1`] = `
<Text
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty 1`] = `
<Text
  accessibilityState={Object {}}
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true 1`] = `
<Text
  accessibilityState={
    Object {
      "checked": true,
    }
  }
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop 1`] = `
<Text
  accessibilityState={
    Object {
      "disabled": false,
    }
  }
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`TouchableHighlight renders correctly 1`] = `
<View
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
  style={Object {}}
>
  <Text>
    Touchable
  </Text>
</View>
`;

@saurabhkacholiya
Copy link

@fabriziobertoglio1987 Pressability is being used in TouchableWithoutFeedback

import Pressability, {
type PressabilityConfig,
} from '../../Pressability/Pressability';

class TouchableWithoutFeedback extends React.Component<Props, State> {
state: State = {
pressability: new Pressability(createPressabilityConfig(this.props)),
};

@fabOnReact
Copy link
Contributor

fabOnReact commented Mar 16, 2021

thanks @saurabhkacholiya but sorry, I think you are wrong.
I would like to prepare a Pull Request for this issue tomorrow.

Your snapshot #30953 (comment) is wrong accessibilityState={ disabled: false}

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState >with value of disabled prop 1`] = `
<Text
 accessibilityState={
   Object {
     "disabled": false,
   }
 }

while the commit 1c7d9c8 has the correct snapshot with accessibilityState={ disabled: true}

exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop: should deep render when not mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}

Facebook Team requested us to build this feature in accessability and change accessabilityState.disabled based on disabled prop.

@fabOnReact
Copy link
Contributor

fabOnReact commented Mar 18, 2021

@saurabhkacholiya as you have already wrote test for this fix, you can check my solution, test it and verify it actually works and then publish a pull request with your github account fabOnReact@153a37c

I did not test it, so you should investigate in details. If you don't want to publish the pull request, I'll be happy to do it myself.
thanks a lot. Bye

@saurabhkacholiya
Copy link

@fabriziobertoglio1987 Sure I would like to give a pull request Thanks a lot. can you just validate the snapshot

exports[`<TouchableWithoutFeedback /> should render as expected 1`] = `
<Text
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} /> should be disabled when disabled is true 1`] = `
<Text
  accessibilityState={
    Object {
      "disabled": true,
    }
  }
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty 1`] = `
<Text
  accessibilityState={Object {}}
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true 1`] = `
<Text
  accessibilityState={
    Object {
      "checked": true,
    }
  }
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

exports[`<TouchableWithoutFeedback disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop 1`] = `
<Text
  accessibilityState={
    Object {
      "disabled": false,
    }
  }
  accessible={true}
  focusable={false}
  onClick={[Function]}
  onResponderGrant={[Function]}
  onResponderMove={[Function]}
  onResponderRelease={[Function]}
  onResponderTerminate={[Function]}
  onResponderTerminationRequest={[Function]}
  onStartShouldSetResponder={[Function]}
>
  Touchable
</Text>
`;

@fabOnReact
Copy link
Contributor

I notice just now

1c7d9c8#diff-466095fa96dd3e4ad5dffc7f31d8da5084c8a0acd3396a8b65b45cd99c48dd4bR320-R330

when you run the test in shallow render, the test output is not correct .. but seems to be ok for the Facebook team ... so I would not worry about that

The important thing is that they work when deep rendering the output

1c7d9c8#diff-466095fa96dd3e4ad5dffc7f31d8da5084c8a0acd3396a8b65b45cd99c48dd4bR283-R304

@amarlette
Copy link
Author

@carloscuesta thank you for opening up a PR for this issue!

@facebook facebook locked as resolved and limited conversation to collaborators Apr 16, 2022
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Apr 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Accessibility Component: TouchableWithoutFeedback Good first issue Interested in collaborating? Take a stab at fixing one of these issues. Platform: Android Android applications. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants