Testing React Apps with Reflect

Create end-to-end tests that are easy to maintain. Get test coverage for complete user workflows, fast.

To create great, maintainable React apps, testing is key. While there are lots of great options for unit testing and component-level testing, options for doing end-to-end testing (testing of entire workflows) have been lacking. Believe it or not, most React developers do this type of testing, known as end-to-end-testing, manually!

The React ecosystem has great options for unit testing and component-level testing. But what about testing how those components interact with each other? Or going even further, how do you test your application as a whole to make sure critical workflows are actually working as intended?

Reflect is an end-to-end testing platform that makes creating end-to-end tests easy.

Why is it so hard to set up automated end-to-end testing for React apps?

Conventional end-to-end frameworks like Selenium, Cypress, and Puppeeter share a number of shortcomings when it comes to testing React apps:

React's virtual DOM can mess up element selection

React uses a process called reconciliation to render changes within your app. As virtual DOM changes are synced with the real DOM, existing DOM nodes get swapped out and replaced with new DOM objects. Conventional end-to-end frameworks need to get a reference to a DOM node in order to execute actions on the app. However with frequent DOM changes, those references can easily get out of date, causing your tests to fail for no good reason.

It's hard to find good, stable selectors

Frameworks like Styled Components and EmotionJS allow React developers to include CSS styling inside their components. While this makes the codebase more tidy, it makes end-to-end testing more difficult because semantically relevant identifiers like ids and human-readable classes are no longer present in the DOM. Instead, auto-generated class names are produced by the CSS-in-JS framework which can change on every build.

Consider the example React component below:

<>
    <GlobalStyle />
    <Container>
        <h2>My React App</h2>
        <Header>Some text here</Header>
        <Block>Text block 1</Block>
        <BoldBlock>Text block 2</BoldBlock>
        <PulseBlock>Text block 3</PulseBlock>
        <Footer>&copy; ACME Inc.</Footer>
    </Container>
</>

After styling from Styled Components is applied, the resultant elements within the DOM end up looking something like this:

<div class="sc-bdVaJa bRHjoZ">
    <h2>My React App</h2>
    <div class="sc-EHOje jjZmSV">Welcome!</div>
    <div class="sc-bwzfXH knDVzB">Text block 1</div>
    <div class="sc-bwzfXH jurZP">Text block 2</div>
    <div class="sc-bwzfXH sc-htpNat dwfcpR">Text block 3</div>
    <div class="sc-bwzfXH sc-ifAKCX druJIC">&copy; Acme Inc.</div>
</div>

To get stable selectors here, developers are forced to add additional attributes so that end-to-end test frameworks can use them as selectors.

No support for visual testing

Think about the bugs you've found in your app. Chances are that some of these bugs are purely visual problems. Things like modals being misplaced, elements getting the wrong styling, or elements on the page getting shifted or obscured. Conventional end-to-end frameworks don't allow you to find these bugs because they operate on DOM elements and are unable to detect visual changes in your app.

A better approach to end-to-end testing with Reflect

Reflect takes a fundamentally different approach compared to conventional end-to-end frameworks. Here's what we're doing differently to ensure Reflect tests are easy to create and maintain:

No installation

Reflect is a no-code testing platform that runs entirely on the web. This means that there's nothing to install; instead of downloading software and running it on your local machine, you instead create tests by recording your actions in real-time. Reflect automatically translates your actions into a repeatable test that you can run anytime. And because everything is web-based, it's easy to hook up your tests to your CI/CD tool and run them on every deploy.

Best-in-class test recorder

Reflect records your actions via a virtual machine that we provision for you on-demand. Because Reflect has complete control of the testing environment, we can do things that no other tool can, such as detect and exactly replicate complex interactions like drag-and-drops, hovers, and file uploads. For React apps, our recorder is resilient to changes synced via the Virtual DOM, which means no more flaky tests.

Resilient selectors that target your underlying React components

Reflect is the only testing tool that can utilize the underlying React component names as selectors. This is important because it means you no longer need to add special attributes so that your test automation has stable selectors. By simply installing our open-source Webpack plugin, you provide Reflect with everything we need to extract the underlying component names for the elements you interact with over the course of a test, and automatically generate selectors that use those component names.

Our Webpack plugin can be installed via the following steps:

Install via npm:
npm install webpack-react-component-name -save-dev
Add the plugin to your Webpack config:
  plugins: [
    new WebpackReactComponentNamePlugin()
  ],

Visual testing as a first-class feature

Conventional end-to-end tools do not have visual testing capabilities built-in, meaning that users either have to forego visual testing entirely or rely on a third-party plugin. With Reflect, Visual Testing is a first-class feature that is purpose-built to help you detect true visual regressions without getting notified about innocuous changes outside the scope of your tests.

Get Started for Free

You can get started using Reflect today and sign up for a free account and create your first test in minutes.

Copyright © 2020 Reflect Software Inc. All Rights Reserved.