Skip to content

Latest commit

History

57 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

react-unit

React Unit is a lightweight unit test library for ReactJS with very few (js-only) dependencies.

By using react-unit you can run your ReactJS unit tests directly from node or gulp without having to install any heavyweight external dependencies (such as jsdom, phantomjs, the python runtime, etc.).

Installation

npm install --save-dev react-unit

and then, in your tests:

varReact=require('react');varcreateComponent=require('react-unit');describe('MyComponent',()=>{it('should echo the value',()=>{varcomponent=createComponent(<MyComponentvalue="hello, world!"/>);varinput=component.findByQuery('input')[0];expect(input.props.value).toBe('hello, world!');});it('should trigger events',()=>{varchangedValue;functiononChange(e){changedValue=e.target.value;}varcomponent=createComponent(<MyComponentonChange={onChange}/>);varinput=component.findByQuery('input')[0];input.onChange({target:{value: 'hi, everyone!'}});expect(changedValue).toBe('hi, everyone!');});});

Note that, while this example is using Jasmine, react-unit should work with any other test language of your choice.

Usage

To use react-unit just require the createComponent function:

varcreateComponent=require('react-unit');

Then use it to create your component:

varcomponent=createComponent(<MyComponentvalue="hello, world!"/>);

or (if, for some reason you are not into JSX):

varcomponent=createComponent(React.createElement(MyComponent,{value: "hello, world!"}));

Now that you have a representation of your component you can use it to find actual HTML elements calling findByQuery:

varallInputs=component.findByQuery('input');varallRows=component.findByQuery('.row');varallFirstNames=component.findByQuery('[name=firstName]');

By now you probably noted that findByQuery takes something suspiciously similar to jQuery selectors. This is not an innocent coincidence, react-unit is bundled with the amazing jQuery Sizzle to allow you to search your react DOM using query selectors.

In addition to findByQuery you can use findBy to test every element using a custom function:

varall=component.findBy(function(){returntrue;});// () => truevarmoreThanTwo=component.findBy(function(c){returnc.props.value>2});

To find elements by their ref attribute, you can use the findByRef method:

varallMyRefs=component.findByRef('myRef');

If you want to find a component using a component variable instead of a string expression, you can use findByComponent:

varcomponent=createComponent.shallow(<CompositeComponent/>);// Note: the .shallow!// or var component = createComponent.interleaved(<CompositeComponent />);varchildren=component.findByComponent(ChildComponent);

Note that findByComponent only works with shallow and interleaved rendering modes. See Rendering Modes below for more details.

If you want to test event handling, you can bind a handler to your component:

varchangeEvent;functionhandler(e){changeEvent=e;}varcomponent=createComponent(<MyComponentonChange={handler}/>);

Then find and interact with any element in the component:

component.findByQuery('some selector')[0].onChange('some event');

Finally assert the event:

expect(changeEvent).toBe('some event');

If at any point you want to inspect the rendered component you can use:

console.log(component.dump());

API Reference

Creating components

// createComponent :: ReactElement -> ComponentcreateComponent=(reactElement)=>Component

Renders reactElement using the deep rendering strategy (see Rendering Modes for more details). Returns the rendered Component.

This method produces a component tree that is somewhat similar to applying ReactDOM.render.

For example:

varcreateComponent=require('react-unit');varcomponent=createComponent(<MyComponent/>);

More examples in test/create-component.jsx.



// createComponent.shallow :: ReactElement -> ComponentcreateComponent.shallow=(reactElement)=>Component

Renders reactElement using the shallow rendering strategy (see Rendering Modes for more details). Returns the rendered Component.

This method produces a shallow component tree. That is, it renders the root component and all the children HTML nodes, stopping at the first child component level.

For example:

varcreateComponent=require('react-unit');varcomponent=createComponent.shallow(<MyComponent/>);

More examples in test/create-component-shallow.jsx.



// createComponent.interleaved :: ReactElement -> ComponentcreateComponent.interleaved=(reactElement)=>Component

Renders reactElement using the interleaved rendering strategy (see Rendering Modes for more details). Returns the rendered Component.

This method produces a component tree that interleaves react components and actual rendered components.

For example:

varcreateComponent=require('react-unit');varcomponent=createComponent.interleaved(<MyComponent/>);

More examples in test/create-component-interleaved.jsx.



Finding components

// findByQuery :: String -> [Component]component.findByQuery=>(sizzleExpression)=>[Components]

Returns all the descendant elements of component matching sizzleExpression.

For example:

varinputs=component.findByQuery('input');

More examples in test/find-by-query.jsx.



// findByComponent :: ReactElement -> [Component]component.findByComponent=>(reactElement)=>[Components]

Returns all the descendant elements of component of type reactElement. Note that findByComponent only works with shallow and interleaved rendering modes. See Rendering Modes below for more details.

For example:

// assuming: var MyItem = React.createClass({ ... });varitems=component.findByComponent(MyItem);

More examples in test/find-by-component.jsx.



// findBy :: (Component -> bool) -> [Component]component.findBy=>(fn)=>[Components]

Returns all the descendant elements of component for whom fn returns true.

For example:

varmoreThanTwos=component.findBy(c=>c.props.value>2);

More examples in test/find-by.jsx.



// findByRef :: String -> [Component]component.findBy=>(ref)=>[Components]

Returns all the descendant elements of component matching the ref attribute.

For example:

varallMyRefs=component.findByRef('myRef');

More examples in test/find-by-ref.jsx.



Inspecting components

// dump :: () -> Stringcomponent.dump=>()=>String

Returns a string representation of the pseudo-HTML of the component. This method is very useful for troubleshooting broken tests.

For example:

varhtml=component.dump();// orconsole.log(component.dump());


component.texts// :: [String]component.text// :: String

Return the text of all the descendant elements of component. texts is a flat array containing the texts of every descendant element in depth order. text behaves like DOMNode.textContent (i.e. component.texts.join('')).

Some examples in test/text.jsx.



// key :: Objectcomponent.props

The props object of component.



// key :: Stringcomponent.key

The key of component.



// ref :: Stringcomponent.ref

The ref of component.



Rendering Modes

Deep rendering (default behavior)

By default react-unit will use a deep (recursive) rendering strategy. This produces an output that is very similar to that of ReactDOM.render.

For example, given:

varPerson=React.createClass({render: function(){varchildren=React.Children.map(this.props.children,(c,i)=><likey={i}>{c}</li>);return<div><h1>{this.props.name}</h1><ul>{children}</ul></div>}});

Calling createComponent in a composite component:

varcomponent=createComponent(<Personname="Homer"><Personname="Bart"/><Personname="Lisa"/><Personname="Maggie"/></Person>);

Results in a representation of the following HTML:

<div><h1>Homer</h1><ul><li><div><h1>Bart</h1><ul></ul></div></li><li><div><h1>Lisa</h1><ul></ul></div></li><li><div><h1>Maggie</h1><ul></ul></div></li></ul></div>

In other words, the output is the HTML that results of calling the render method of every component. Note that, as a side-effect of deep rendering, component tags (e.g. <Person/>) were erased from the HTML representation.

In the example above you find Lisa with:

varlisa=component.findByQuery('div > ul > li > div > h1')[1];

On the flip side, you cannot use findByQuery to find your components because, after rendering, they were replaced by the HTML they generate in their render method:

varpersons=component.findByQuery('Person');expect(persons.length).toEqual(0);

Shallow rendering

Sometimes you might want to stop rendering after the first level of components. In true unit test spirit you would like to just test a component assuming the components it depends upon are working.

To achieve this you can use createComponent.shallow as follows:

varcomponent=createComponent.shallow(<Personname="Homer"><Personname="Bart"/><Personname="Lisa"/><Personname="Maggie"/></Person>);

And the result would be a representation of the following pseudo-HTML:

<div><h1>Homer</h1><ul><li><Personname="Bart"/></li><li><Personname="Lisa"/></li><li><Personname="Maggie"/></li></ul></div>

To find Lisa you could use any of the following:

varlisaByAttr=component.findByQuery('Person[name=Lisa]')[0];varlisaByTagAndOrder=component.findByQuery('Person')[1];varlisaByCompAndOrder=component.findByComponent(Person)[1];

And access the properties as usual:

expect(lisaByAttr.prop('name')).toEqual('Lisa');

Interleaved rendering

This rendering mode is similar to the deep mode above with the exception that components are NOT erased form the HTML representation. This means that you can mix and match HTML tags and react components in your findByQuery selectors.

To use interleaved rendering call createComponent.interleaved as follows:

varcomponent=createComponent.interleaved(<Personname="Homer"><Personname="Bart"/><Personname="Lisa"/><Personname="Maggie"/></Person>);

The result would be a representation of the following pseudo-HTML:

<Personname="Homer"><div><h1>Homer</h1><ul><li><Personname="Bart"><div><h1>Bart</h1><ul></ul></div></Person></li><li><Personname="Lisa"><div><h1>Lisa</h1><ul></ul></div></Person></li><li><Personname="Maggie"><div><h1>Maggie</h1><ul></ul></div></Person></li></ul></div></Person>

And you can find components with:

varlisaComp=component.findByQuery('Person[name=Lisa]')[0];varlisaCompAlt=component.findByComponent(Person)[2];varlisaName=component.findByQuery('Person[name=Lisa] h1')[0];varlisaNameAlt=lisaComp.findByQuery('h1')[0];

More info

Note that testing stateful components require additional effort. See test/stateful.jsx for more details.

For more examples on how to test events refer to test/events.jsx.

For more examples on finding elements by query selectors refer to test/find-by-query.jsx.

For more examples on finding element using a custom function refer to test/find-by.jsx.

About

Lightweight unit test library for ReactJS

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages