This repository has been archived by the owner on Sep 20, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[added] much better selector support
- Loading branch information
Showing
11 changed files
with
577 additions
and
226 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
React TestUtils utils | ||
======== | ||
|
||
A simple jquery like api wrapper for the React TestUtils to make them a bit friendlier to use. | ||
|
||
Updates for react 0.14, works with Stateless Components and you can scry and filter on DOM components | ||
as well. | ||
|
||
### Traditional DOM rendering | ||
|
||
```js | ||
var $r = require('react-testutil-query') | ||
|
||
var elements = ( | ||
<MyComponent> | ||
<MyInput/> | ||
<div className='fun-div'> | ||
<MyInput/> | ||
</MyComponent> | ||
) | ||
|
||
var $root = $r(elements) // renders and returns a wrapped instance | ||
|
||
$r($root) // | calling it again won't rerender or rewrap | ||
$r($root[0]) // | | ||
|
||
//-- simple selector syntax -- | ||
$root.find('.fun-div') //class | ||
$root.find('div') // tag name | ||
$root.find(MyInput) // component type | ||
|
||
$root.find(':dom') // all dom nodes | ||
$root.find(':composite') // all non DOM components | ||
|
||
$root.find() // everything! all descendents | ||
|
||
//-- like jquery you get an arraylike thing | ||
$root.find(MyInput).length // 2 | ||
|
||
$root.find(MyInput).each( (component, idx) => /*do something */) | ||
|
||
// use the index or `get()` to unwrap the collection into a single component or real array | ||
$root.find('.fun-div')[0] | ||
|
||
|
||
$root.find(MyInput).first() | ||
$root.find(MyInput).last() | ||
|
||
// you can still get the implicit asserts for finding single components | ||
$root.find('.fun-div').only() // throws a TypeError .length === 0 | ||
$root.single('.fun-div') // is the same thing | ||
|
||
|
||
// -- getting DOM nodes | ||
$root.single('.fun-div').dom() // returns the single DOM node | ||
$root.find(MyInput).dom() //returns an array of DOM nodes | ||
|
||
// -- events | ||
$root.find(MyInput).trigger('change', { target: { value: 6 }}) // triggers onChange for all of them | ||
``` | ||
|
||
### Shallow rendering | ||
|
||
We can use an even more powerful selector syntax will shallow rendering | ||
|
||
```js | ||
var $ = require('react-testutil-query/shallow'); | ||
|
||
let label = 'list item'; | ||
|
||
let BasicList = props => <ul>{props.children}</ul> | ||
|
||
let DivList = ()=> ( | ||
<div> | ||
<BasicList className='my-list'> | ||
<li className='foo'>hi 1</li> | ||
<li className='foo'>hi 2</li> | ||
<li aria-label={label}>hi 3</li> | ||
</BasicList> | ||
</div> | ||
) | ||
|
||
|
||
let $root = $(<DivList); | ||
|
||
$root.find('.my-list > li.foo').length // 2 | ||
|
||
$root.find('.my-list').children('.foo').length // 2 | ||
|
||
$root.find('div li[aria-label="list item"]').length // 1 | ||
|
||
// you can even use es6 template strings to write | ||
// selectors for your custom components | ||
$root.find($.s`${BasicList} > li.foo`).length // 2 | ||
|
||
//or for prop values | ||
$root.find($.s`li[aria-label=${label}]`).length // 1 | ||
|
||
$root.find(BasicList) | ||
.children() | ||
.filter(element => element.props.className === 'foo') | ||
.length // 2 | ||
|
||
$root.find(BasicList).is('.my-list').length // true | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "react-testutil-query", | ||
"version": "2.2.0", | ||
"description": "small wrapper around react test utils so I don't have to write long method names", | ||
"main": "index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/jquense/react-testutil-query" | ||
}, | ||
"keywords": [ | ||
"react", | ||
"test", | ||
"query" | ||
], | ||
"author": "jquense", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/jquense/react-testutil-query/issues" | ||
}, | ||
"homepage": "https://github.com/jquense/react-testutil-query", | ||
"peerDependencies": { | ||
"react": ">=0.14.0-rc1", | ||
"react-dom": ">=0.14.0-rc1" | ||
}, | ||
"dependencies": { | ||
"bill": "^1.0.4", | ||
"dom-helpers": "^2.4.0", | ||
"react-addons-test-utils": "^0.14.0-rc1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
'use strict'; | ||
|
||
exports.__esModule = true; | ||
|
||
var _templateObject = _taggedTemplateLiteralLoose(['', ''], ['', '']); | ||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
|
||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
|
||
function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } | ||
|
||
var _react = require('react'); | ||
|
||
var _react2 = _interopRequireDefault(_react); | ||
|
||
var _reactAddonsTestUtils = require('react-addons-test-utils'); | ||
|
||
var _reactAddonsTestUtils2 = _interopRequireDefault(_reactAddonsTestUtils); | ||
|
||
var _bill = require('bill'); | ||
|
||
var isRtq = function isRtq(item) { | ||
return item && item.__isRTQ; | ||
}; | ||
|
||
rtq.s = rtq.selector = _bill.selector; | ||
|
||
exports['default'] = rtq; | ||
|
||
function match(selector, tree, includeSelf) { | ||
if (typeof selector === 'function') selector = _bill.selector(_templateObject, selector); | ||
|
||
return _bill.match(selector, tree, includeSelf); | ||
} | ||
|
||
function render(element) { | ||
var root = element; | ||
|
||
if (!(typeof root.type === 'string' && root.type.toLowerCase() === root.type)) { | ||
var renderer = _reactAddonsTestUtils2['default'].createRenderer(); | ||
renderer.render(element); | ||
root = renderer.getRenderOutput(); | ||
} | ||
|
||
return { | ||
root: root, | ||
setProps: function setProps(props) { | ||
return render(_react.cloneElement(element, props)); | ||
} | ||
}; | ||
} | ||
|
||
function rtq(element) { | ||
var context, rerender; | ||
|
||
if (_reactAddonsTestUtils2['default'].isElement(element)) { | ||
var _render = render(element); | ||
|
||
var root = _render.root; | ||
var setProps = _render.setProps; | ||
|
||
element = context = root; | ||
rerender = setProps; | ||
} else if (isRtq(element)) { | ||
context = element.root; | ||
element = element.get(); | ||
//rerender = element._rerender | ||
} | ||
|
||
return new ShallowCollection(element, context, rerender); | ||
} | ||
|
||
var ShallowCollection = (function () { | ||
function ShallowCollection(elements, root, rerender) { | ||
_classCallCheck(this, ShallowCollection); | ||
|
||
elements = [].concat(elements).filter(function (el) { | ||
return _react.isValidElement(el); | ||
}); | ||
|
||
var idx = -1; | ||
|
||
while (++idx < elements.length) this[idx] = elements[idx]; | ||
|
||
this._rerender = rerender; | ||
this.length = elements.length; | ||
this.root = root; | ||
} | ||
|
||
ShallowCollection.prototype.setProps = function setProps(props) { | ||
this._rerender && this._rerender(props); | ||
return this; | ||
}; | ||
|
||
ShallowCollection.prototype.each = function each(cb) { | ||
var idx = -1, | ||
len = this.length; | ||
while (++idx < len) cb(this[idx], idx, this); | ||
return this; | ||
}; | ||
|
||
ShallowCollection.prototype.get = function get() { | ||
var result = []; | ||
this.each(function (el) { | ||
return result.push(el); | ||
}); | ||
return result; | ||
}; | ||
|
||
ShallowCollection.prototype.reduce = function reduce(cb, initial) { | ||
return new ShallowCollection([].reduce.call(this, cb, initial), this.root); | ||
}; | ||
|
||
ShallowCollection.prototype.map = function map(cb) { | ||
var result = []; | ||
this.each(function (v, i, l) { | ||
return result.push(cb(v, i, l)); | ||
}); | ||
|
||
return new ShallowCollection(result, this.root); | ||
}; | ||
|
||
ShallowCollection.prototype.find = function find(selector) { | ||
return this.reduce(function (result, element) { | ||
return result.concat(match(selector, element)); | ||
}, []); | ||
}; | ||
|
||
ShallowCollection.prototype.children = function children(selector) { | ||
return this.reduce(function (result, element) { | ||
return result.concat(element.props.children || []); | ||
}, []).filter(selector); | ||
}; | ||
|
||
ShallowCollection.prototype.filter = function filter(selector) { | ||
if (!selector) return this; | ||
|
||
if (typeof selector === 'function') return new ShallowCollection([].filter.call(this, selector), this.root); | ||
|
||
var matches = match(selector, this.root); | ||
|
||
return new ShallowCollection([].filter.call(this, function (el) { | ||
return matches.indexOf(el) !== -1; | ||
}), this.root); | ||
}; | ||
|
||
ShallowCollection.prototype.is = function is(selector) { | ||
return this.filter(selector).length === this.length; | ||
}; | ||
|
||
return ShallowCollection; | ||
})(); | ||
|
||
module.exports = exports['default']; |
Oops, something went wrong.