jsdf / react-native-htmlview

A React Native component which renders HTML content as native views
ISC License
2.71k stars 467 forks source link

How to add TestID in order to use for automation #274

Open PawarSharadB opened 4 years ago

PawarSharadB commented 4 years ago

I am trying to add TestID for htmlView element for automation purpose .Somehow i am unable to add it . Is there any ways to add ?

joshchoo commented 3 years ago

For anyone who has the same question, the testID can be attached to HtmlView's underlying View container by passing through the rootComponentProps:

<HtmlView
  ...
  rootComponentProps={{
    testID: 'myTestId'
  }}
/>
iMaupin commented 2 years ago

@joshchoo is there a way to pass the testID here to the native components? I am rendering some Text components from HTML and I would like to pass a testID directly to the text components themselves.

joshchoo commented 2 years ago

@iMaupin, sorry I didn't understand what you meant. Do you have an example of what you'd like to achieve ideally?

iMaupin commented 2 years ago

@joshchoo ok for further clarification: I am using detox to write automated tests and would love to be able to access the text displayed by an HTMLView component.

with a normal react native text component this can be accomplished by calling the getAtributes() method on a testID that is assigned to that Text component. The value for the text key for the resulting object is a string of the displayed text. Is there a way that similar results may be attained within an HTMLView?

joshchoo commented 2 years ago

@iMaupin, if I understand correctly is this what you're hoping to achieve?

Patching react-native-htmlview to read testid attributes and set them:

diff --git a/node_modules/react-native-htmlview/htmlToElement.js b/node_modules/react-native-htmlview/htmlToElement.js
index 5bcca40..4a21133 100644
--- a/node_modules/react-native-htmlview/htmlToElement.js
+++ b/node_modules/react-native-htmlview/htmlToElement.js
@@ -100,6 +100,8 @@ export default function htmlToElement(rawHtml, customOpts = {}, done) {
           }
         }

+        let testID = node.attribs?.testid;
+
         let linebreakBefore = null;
         let linebreakAfter = null;
         if (opts.addLineBreaks) {
@@ -150,6 +152,7 @@ export default function htmlToElement(rawHtml, customOpts = {}, done) {
           <NodeComponent
             {...opts.nodeComponentProps}
             key={index}
+            testID={testID}
             onPress={linkPressHandler}
             style={!node.parent ? styles[node.name] : null}
             onLongPress={linkLongPressHandler}

Rendered output:

import React from 'react';
import HTMLView from 'react-native-htmlview';
import TestRenderer from 'react-test-renderer';

describe('HTMLView', () => {
  it('renders', () => {
    const testRenderer = TestRenderer.create(
      <HTMLView
        value={
          '<p testid="foo">This is Foo.</p><p testid="bar">This is Bar.</p>'
        }
      />,
    );
    console.log(testRenderer.toJSON());

    /* Result as JSX:
        <View>
          <Text
            onLongPress={null}
            onPress={null}
            testID="foo"
          >
            <Text
              style={
                Array [
                  null,
                  Object {},
                ]
              }
            >
              This is Foo.
            </Text>
          </Text>
          <Text
            onLongPress={null}
            onPress={null}
            testID="bar"
          >
            <Text
              style={
                Array [
                  null,
                  Object {},
                ]
              }
            >
              This is Bar.
            </Text>
          </Text>
        </View>
    */
  });
});

Sidenote: Detox (or React-Native in general) may have trouble handling nested text elements.

iMaupin commented 2 years ago

@joshchoo awesome! This patch does exactly what I needed. Thank you so much!

joshchoo commented 2 years ago

Glad I could help!