So, I've been using emotion-js
for a while, and I love it! But I really hate e2e tests for that. All selectors look like this: div > div > div > p
, because emotion
injects classnames which are random-generated strings.
So I thought of injecting data-
attributes with DisplayName
to each element to be able to test them in more clean way: [data-test-id*="DateButton"]
or something like that. So I wrote this simple wrapper:
https://gist.github.com/sergeyvlakh/3072a4e2e27456bda853a1e1a213a568
And I use it like this:
import Injector from './injector';
export default props =>
(
<Injector>
<MyReactTree />
</Injector>
)
The problem here is what I'm not "dynamically" inject data attribute. I want to use it like any HoC from recompose
:
export default Injector(App)
OR even with dynamic prop name like: export default Injector('data-test-id')(App)
.
But...children for Injector
will be undefined in that case, so I don't know how to proceed :)
UPDATE: Thanks to remix23 I did this way: https://gist.github.com/sergeyvlakh/f99310cdef018c06451333a36e764372
However I strongly recommend to use his code.
A Practical Use for Recursion in React Follow along to understand the ins and outs of a working React Tree component powered by recursion + React rendering. Giving our component nested data in the following shape, we'll now have a functioning, modular, and recursive component ready for use!
To pass props, add them to the JSX, just like you would with HTML attributes. To read props, use the function Avatar({ person, size }) destructuring syntax. You can specify a default value like size = 100 , which is used for missing and undefined props.
Instead, to pass all React props from parent to child at once, you need to take advantage of the spread operator ( ... ). The spread operator lets you pass the entire props object to a child component as that child's props object.
You can inject props to any React element by using React.cloneElement(element, newPropsToMerge, newChildren)
You can do it recursively to follow chilren in depth by accessing each element children and so forth.
And maybe more costly but more straightforward this should work also:
function Injector(Target) {
class InjectedTarget extends Component {
render() {
const { chilren, ...rest } = this.props;
return (
<Target
data-test-id={Target.DisplayName}
{...rest}
>
{React.Children.map(children, (child) => {
const isComponent =
child &&
child.type &&
typeof child.type !== 'string' &&
Object.prototype.isPrototypeOf.apply(
React.Component.prototype,
[child.type.prototype]
);
if (!isComponent) {
return child;
}
return React.createElement(Injector(child.type), { ...child.props, 'data-test-id': Target.DisplayName });
})}
</Target>
);
}
}
return InjectedTarget;
}
I think that will be awfull performance wise, but this is for testing right?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With