Skip to content

fgnass/retractor

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

E2E Testing for React Apps

Retractor exposes the internals of a React application for end-to-end testing purposes. This allows you to select DOM nodes based on the name of the React Component that rendered the node as well as its state or properties.

A retractor is a surgical instrument with which a surgeon can either actively separate the edges of a surgical incision or wound, or can hold back underlying organs and tissues, so that body parts under the incision may be accessed. – Wikipedia

retractor

Installation

npm install --save retractor

Setup

Retractor uses the React Dev-Tools hooks to expose your app's internals. In order for this to work, Retractor must be loaded before React gets initialized.

In a webpack based setup this can be achieved by adding retractor/client to the beginning of the entry array:

module.exports = {
  entry: [
    'retractor/client',
    './index' //your application entry
  ],
  output: {},
  plugins: [],
  module: {
    loaders: []
  }
}

You can verify that Retractor is installed by typing __retractor in your Browser's console.

Interacting with Retractor via Selenium

Once your app exposes the Retractor API you can interact with it via Selenium:

import React from 'react';
import byJSX from 'retractor';
import webdriver from 'selenium-webdriver';

import TodoItem from '../components/TodoItem';

const driver = new webdriver.Builder().forBrowser('phantomjs').build();

driver.get('http://localhost:3000/');

// Find all TodoItems
driver.findElements(byJSX(<TodoItem />));

// Find one TodoItem with a given text
driver.findElement(byJSX(
  <TodoItem todo={{ text: 'Use retractor' }} />
));

Features

The Retractor JSX bindings allow to query the DOM nodes of your components in an intuitive way. You just have to write plain JSX expressions to search and filter the components you would like to interact with.

Query

To query components you have to use the byJSX locator. By default it will return all the DOM nodes of the mounted components matching that expression.

import byJSX from 'retractor';
import webdriver from 'selenium-webdriver';

const driver = new webdriver.Builder()

driver.findElements(byJSX(<TodoItem />));

Filter by props

It's also possible to filter components based on their internal data structure (props). Just define the filter criteria as props in the JSX expression. For example, given two TodoItems, calling byJSX with props {complete: false} will return the one but not the other.

driver.findElements(byJSX(<TodoItem todo={{ title: 'retractor' }} />));
driver.findElements(byJSX(<TodoItem todo={{ title: 'retractor', completed: false }} />));
driver.findElements(byJSX(<TodoItem editing />));

Retractor uses deep-match internally to support sophisticated filtering. This also allows you to use RegEx patterns for your prop filters.

driver.findElements(byJSX(<TodoItem todo={{ title: /retractor/ }} />))

Scoped lookups

//TODO verify and document

driver.findElements(
  byJSX(<TodoApp model={{ key: 'todolist-2' }} />)).then(
  byJSX(<TodoItem todo={{ title: /Retractor/ }} />)
);

React warnings

Note: While executing your tests you might encounter React warnings about not-fulfilled propTypes of components that you're trying to lookup. It's safe to ignore those because retractor never actually executes or mounts a component. It simply offers JSX syntax as syntactic sugar, which gets translated by retractor internally to perform the query.

A workaround to disable the warnings is running your tests in a environment other than development

"scripts":
  "test-e2e": "NODE_ENV=production mocha ..."
}

Retractor Client API

//TODO __retractor.findDOMNodes()

Integrating with Selene

Working with the plain webdriver API like in the example above is often quite verbose. Retractor provides a plugin for Selene, a 100% backwards compatible wrapper around the official Selenium driver. With Selene the very same example can be written as:

import React from 'react';
import selene from 'selene';
import retractor from 'retractor/selene';

import TodoItem from '../components/TodoItem';

const se = selene({browser: 'phantomjs'}).use(retractor);

se.get('http://localhost:3000/');

// Find all TodoItems
se.findAll(<TodoItem />);

// Find one TodoItem with a given text
se.find(<TodoItem todo={{ text: 'Use retractor' }} />);

About

Expose react internals for E2E testing

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 75.9%
  • CSS 23.1%
  • HTML 1.0%