The TestCafe Selector function allows you to use CSS selectors to find the elements that you need to test in the DOM. Using CSS selectors is extremely convenient, and many other testing libraries use the same approach. When using TestCafe to test a React application, using plain CSS selectors will definitely get the job done, is normally the route I take. But it's not the only option.
TestCafe has React-specific selectors that allow you to traverse a component hierarchy to select components by name, by property value, and even the component's state.
Let's say we have the above component tree. We could use React selectors to get the ProductList component like this:
The ReactSelector function takes in a component name and should start with the root component. The comparable CSS selector for the ProductList variable we have above would be:
Selector('.app > .productList');
ProductList would need to be an immediate child of the App component. This can get annoying since in a more complex React app, there could be many levels of nested components to find. Luckily, TestCafe thought of that:
The findReact function allows you to search for a react component nested inside of another component. It's very similar to the find method on the Selector object.
Selector('#component').find('h1');
withProps({ … })
Selecting components by name is quick and easy. But in a real application having something more exact would be better. You could either use more selectivity in a CSS selector, or you can use ReactSelector's withProps function to find a component with specific props.
withProps will work even if your property value is an object, with matching either being partial or exact.
The more you know about your React components, the easier it'll be to find them in the DOM. You could bypass all CSS selectors if you wanted to.
You would need to be careful with this approach, however. If you are doing exact object matching in your selector, but then decide to add a new prop to the object in your component, you would need to update the end to end test as well. I personally don't like to tie my testing code to my application code as much, since it just makes for something else I need to think about while working on a feature. I'd just recommend being careful not to overdo the exact match, especially on complex objects, to save yourself some headaches.
getReact()
There are some test scenarios where you would like to test that a property was updated correctly, or check the value of state. Ideally, you would use something like react-testing-library to test these types of interactions. If you would rather check the internals in your end to end test though, the getReact function is what you'll need. The getReact function returns a client function that resolves with an object of component properties and state.
With this info you can run expectations against state values or component properties:
I would still recommend a Jest test to make these checks, but sometimes that's not always the easiest solution, especially if you have a lot of complex setup involved. You could use getState in a TestCafe test and run it in chrome headless mode. That may run fast enough to make it feel like a Jest test, depending on your app. Try it out :)
In Conclusion
TestCafe is a wonderful tool for creating end-to-end tests and is really transforming how developers approach testing. There are smart test actions and assertions with automatic waiting for elements to appear, no need for webdriver, and full TypeScript support. Along with React specific selectors, there are other selector libraries for Vue, AngularJS, Angular, and Aurelia. I think there are a lot of benefits to using React Selectors in a React app, and you should give them a try while writing your next test!
The more you know about your React components, the easier it'll be to find them in the DOM. You could bypass all CSS selectors if you wanted to.
You would need to be careful with this approach, however. If you are doing exact object matching in your selector, but then decide to add a new prop to the object in your component, you would need to update the end to end test as well. I personally don't like to tie my testing code to my application code as much, since it just makes for something else I need to think about while working on a feature. I'd just recommend being careful not to overdo the exact match, especially on complex objects.
Follow me on twitter 😀