cavy icon indicating copy to clipboard operation
cavy copied to clipboard

[RFC] Add jsx pragma integration

Open rams23 opened this issue 4 years ago • 5 comments

Hi. First of all thank you for the cavy library. I started using it and I was thinking if can be possible to reduce the normal code impact, removing wrap functions, useCavy, HOC etc with a jsx pragma that replaces createElement with a simple wrap.

I already executed some test and created a custom jsx function like this:

// index.js of cavy-jsx
let testStore = null;

export function setTestStore(store) {
  testStore = store;
}

export function cavyJsx(type, props, children) {

  if ('cavyTestId' in props && testStore) {
    const WrappedType = wrap(type);
    const generateTestHook = cavy(testStore);
    const newProps = {...props, ref: generateTestHook(props.cavyTestId)};
    return React.createElement(WrappedType, newProps, children);
  }

  return React.createElement.apply(undefined, arguments);
}



//index.test.js
import { setTestStore } from "cavy-jsx";

const testHookStore = new TestHookStore();

setTestStore(testHookStore);



//LoginScreen.js
/** @jsx cavyJsx */
/** @jsxFrag React.Fragment */
import { cavyJsx } from 'cavy-jsx';
...
<TextInput
          value={password}
          cavyTestId="LoginScreen.PasswordInput"
          onChangeText={setPassword}
/>
<TextInput
          value={password}
          cavyTestId="LoginScreen.PasswordInput"
          onChangeText={setPassword}
/>
<Button 
          cavyTestId="LoginScreen.Button"
          onPress={doLogin}
>
      <Text>Login</Text>
</Button>

this way the code stays clean but cavy still works and can also wrap components automatically. I was also trying to configure @babel/plugin-transform-react-jsx to automatically inject the pragma with no success but i thing it can be feasible. The solution with the eplicit jsx pragma already works.

What do you thing?

rams23 avatar Mar 22 '20 14:03 rams23

@rams23 this is a really interesting approach, thank you for investigating and trying stuff out. Last time we explored this, we were looking at a possible Babel plugin but I quite like the JSX pragma idea.

We'll be exploring this further!

jalada avatar Mar 22 '20 17:03 jalada

Thanks for the fast reply @jalada . I'll let you know what I can find and maybe submit a PR. The pragma is working but it must by spread everywhere. I'm trying to exploit @wordpress/babel-plugin-import-jsx-pragma and @babel/plugin-transform-react-jsx to directly inject it. Another thing that I'm trying to do is use declaration merging to add cavyTestId as default props (like children) to Component definition.

rams23 avatar Mar 22 '20 17:03 rams23

For anyone coming to this; see my comment on the PR for an update!

jalada avatar Aug 24 '20 09:08 jalada

that's a great idea @rams23 @jalada @rams23 what do you think about reusing the standard "testID" prop instead of introducing a new additional prop? the benefit i see:

  1. not need to introduce new prop
  2. for existing code base already includes testing with react-testing or other - this would be the complementary without the need to change/add any code for adding cavy.

orizens avatar Jan 06 '21 16:01 orizens

@orizens agreed, no reason why not. I'd really love one day for React Native to support querying for elements in the tree with the testID prop directly without having to build a hack like this. But in the mean time, using a pragma to get access would be an option.

jalada avatar Jan 06 '21 16:01 jalada