├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | COPYRIGHT (c) 2016 James Kyle 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [**Deprecated** - You're probably looking for the package of the same name in the React repo!](https://github.com/facebook/react/tree/master/packages/react-test-renderer) 2 | 3 | --- 4 | 5 | # react-test-renderer 6 | 7 | > A lightweight solution to testing fully-rendered React Components 8 | 9 | ## Installation 10 | 11 | ```sh 12 | $ npm install react-test-renderer 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```js 18 | const render = require('react-test-renderer'); 19 | 20 | const stub = createStub(); 21 | 22 | render() 23 | .find(element => element.type === 'button') 24 | .simulate('click'); 25 | 26 | assert.ok(stub.called); 27 | ``` 28 | 29 | ## API 30 | 31 | ```js 32 | interface Searchable { 33 | find(predicate: (element: RenderedElement) => boolean): RenderedElement; 34 | findAll(predicate: (element: RenderedElement) => boolean): Array; 35 | findComponent(component: ReactComponent): RenderedComponent; 36 | findAllComponent(component: ReactComponent): RenderedComponent; 37 | } 38 | 39 | interface RenderedElement mixins Searchable { 40 | type: string; 41 | props: Object; 42 | simulate(eventName: string, eventOpts?: Object): void; 43 | } 44 | 45 | interface RenderedComponent mixins Searchable { 46 | root: RenderedElement; 47 | refs: { [name: string]: RenderedElement }; 48 | } 49 | 50 | interface RenderedTree mixins Searchable {} 51 | 52 | function render(ReactElement): RenderedTree 53 | ``` 54 | 55 | 56 | ## Examples 57 | 58 | Find an element: 59 | 60 | ```js 61 | var tree = render( 62 |
63 |

Hello World

64 |

...

65 |
66 | ); 67 | 68 | var heading = tree.find(element => element.type === 'h1'); 69 | 70 | assert.equal(heading.type, 'h1'); 71 | assert.deepEqual(heading.props, { 72 | children: 'Hello World' 73 | }); 74 | ``` 75 | 76 | Simulate an event on a component: 77 | 78 | ```js 79 | var stub = createStub(); 80 | var tree = render( 81 |
82 | 83 |
84 | ); 85 | 86 | tree.find(element => element.type === 'button') 87 | .simulate('click'); 88 | 89 | assert.ok(stub.called); 90 | ``` 91 | 92 | ## Usage with jsdom 93 | 94 | Using [jsdom](https://github.com/tmpvar/jsdom) you can run this test renderer 95 | entirely in Node. Just set this up before you run your tests: 96 | 97 | ```sh 98 | $ npm install --save-dev jsdom 99 | ``` 100 | 101 | ```js 102 | var jsdom = require('jsdom').jsdom; 103 | 104 | global.window = jsdom(undefined, { url: 'about:blank' }).defaultView; 105 | global.document = global.window.document; 106 | ``` 107 | 108 | > Note: This was tested using jsdom@9 109 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var TestUtils = require('react-addons-test-utils'); 2 | 3 | var internalInstanceKey; 4 | var INTERNAL_INSTANCE_KEY = /^__reactInternalInstance/; 5 | 6 | function getInternalInstance(element) { 7 | if (element._reactInternalComponent) { 8 | return element._reactInternalComponent; 9 | } 10 | 11 | if (!internalInstanceKey) { 12 | internalInstanceKey = Object.keys(element).find(function(key) { 13 | return INTERNAL_INSTANCE_KEY.test(key); 14 | }); 15 | } 16 | 17 | return element[internalInstanceKey]; 18 | } 19 | 20 | function find(target, predicate) { 21 | return findAll(target, predicate)[0]; 22 | } 23 | 24 | function findAll(target, predicate) { 25 | return TestUtils.findAllInRenderedTree(target, function(item) { 26 | if (TestUtils.isCompositeComponent(item)) { 27 | return false; 28 | } 29 | 30 | return predicate(createRenderedElement(item)); 31 | }).map(createRenderedElement); 32 | } 33 | 34 | function findComponent(target, component) { 35 | return findAllComponent(target, component)[0]; 36 | } 37 | 38 | function findAllComponent(target, component) { 39 | return TestUtils.findAllInRenderedTree(target, function(item) { 40 | return TestUtils.isCompositeComponentWithType(item, component); 41 | }).map(createRenderedComponent); 42 | } 43 | 44 | function createSearchMethods(target) { 45 | return { 46 | find: function(predicate) { 47 | return find(target, predicate); 48 | }, 49 | findAll: function(predicate) { 50 | return findAll(target, predicate); 51 | }, 52 | findComponent: function(component) { 53 | return findComponent(target, component); 54 | }, 55 | findAllComponent: function(component) { 56 | return findAllComponent(target, component); 57 | } 58 | }; 59 | } 60 | 61 | function createSimulateMethod(element) { 62 | return function simulate(eventName, eventOpts) { 63 | TestUtils.Simulate[eventName](element, eventOpts); 64 | }; 65 | } 66 | 67 | function createRenderedElement(element) { 68 | var currentElement = getInternalInstance(element)._currentElement; 69 | 70 | return { 71 | type: currentElement.type, 72 | props: currentElement.props, 73 | simulate: createSimulateMethod(element) 74 | }; 75 | } 76 | 77 | function createRenderedComponent(component) { 78 | var renderedComponent = component._reactInternalInstance._renderedComponent; 79 | var rootElement = renderedComponent._nativeNode || renderedComponent._nodeWithLegacyProperties; 80 | var root = createRenderedElement(rootElement); 81 | var refs = {}; 82 | 83 | Object.keys(component.refs).forEach(function(ref) { 84 | refs[ref] = createRenderedElement(component.refs[ref]); 85 | }); 86 | 87 | var methods = createSearchMethods(component); 88 | 89 | return Object.assign({ 90 | root: root, 91 | refs: refs, 92 | }, createSearchMethods(component)); 93 | } 94 | 95 | function createRenderedTree(tree) { 96 | return createSearchMethods(tree); 97 | } 98 | 99 | function render(element) { 100 | return createRenderedTree(TestUtils.renderIntoDocument(element)); 101 | } 102 | 103 | module.exports = render; 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-test-renderer", 3 | "version": "1.1.0", 4 | "description": "A lightweight solution to testing fully-rendered React Components", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "author": "James Kyle ", 10 | "license": "ISC", 11 | "dependencies": { 12 | "object-assign": "^4.1.0", 13 | "react-addons-test-utils": "^0.14.0 || ^15.0.0" 14 | }, 15 | "devDependencies": { 16 | "jsdom": "^9.1.0", 17 | "mocha": "^2.4.5", 18 | "react": "^0.14.0 || ^15.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var React = require('react'); 3 | var jsdom = require('jsdom').jsdom; 4 | var render = require('./'); 5 | 6 | global.window = jsdom(undefined, { url: 'about:blank' }).defaultView; 7 | global.document = global.window.document; 8 | 9 | var Button = React.createClass({ 10 | render: function() { 11 | return React.createElement('button', { 12 | ref: 'button', 13 | className: 'btn btn-primary', 14 | onClick: this.props.onClick 15 | }, this.props.children); 16 | } 17 | }); 18 | 19 | var Application = React.createClass({ 20 | render: function() { 21 | return React.createElement('section', { 22 | ref: 'section' 23 | }, 24 | React.createElement('h1', { 25 | ref: 'heading' 26 | }, 'Hello World'), 27 | React.createElement(Button, { 28 | ref: 'button', 29 | onClick: this.props.onClick 30 | }, 'Click Me!'), 31 | React.createElement(Button, { 32 | ref: 'button', 33 | onClick: this.props.onClick 34 | }, 'Click Me Too!') 35 | ); 36 | } 37 | }); 38 | 39 | function createStub() { 40 | return function stub() { 41 | stub.called = true; 42 | }; 43 | } 44 | 45 | describe('render()', function() { 46 | it('should create a tree', function() { 47 | var tree = render(React.createElement(Application)); 48 | 49 | assert.ok(tree.find); 50 | assert.ok(tree.findAll); 51 | assert.ok(tree.findComponent); 52 | assert.ok(tree.findAllComponent); 53 | }); 54 | 55 | it('should find an element', function() { 56 | var stub = createStub(); 57 | var tree = render(React.createElement(Application, { 58 | onClick: stub 59 | })); 60 | 61 | var heading = tree.find(function(element) { 62 | return element.type === 'h1'; 63 | }); 64 | 65 | assert.equal(heading.type, 'h1'); 66 | assert.deepEqual(heading.props, { 67 | children: 'Hello World' 68 | }); 69 | }); 70 | 71 | it('should find a deep element', function() { 72 | var stub = createStub(); 73 | var tree = render(React.createElement(Application, { 74 | onClick: stub 75 | })); 76 | 77 | var heading = tree.find(function(element) { 78 | return element.type === 'button'; 79 | }); 80 | 81 | assert.equal(heading.type, 'button'); 82 | assert.deepEqual(heading.props, { 83 | onClick: stub, 84 | className: 'btn btn-primary', 85 | children: 'Click Me!' 86 | }); 87 | }); 88 | 89 | it('should find multiple elements', function() { 90 | var stub = createStub(); 91 | var tree = render(React.createElement(Application, { 92 | onClick: stub 93 | })); 94 | 95 | var elements = tree.findAll(function(element) { 96 | return element.type === 'h1' || element.type === 'button'; 97 | }); 98 | 99 | assert.equal(elements[0].type, 'h1'); 100 | assert.equal(elements[1].type, 'button'); 101 | assert.equal(elements[2].type, 'button'); 102 | }); 103 | 104 | it('should be able to find a component', function() { 105 | var stub = createStub(); 106 | var tree = render(React.createElement(Application, { 107 | onClick: stub 108 | })); 109 | 110 | var button = tree.findComponent(Button); 111 | 112 | assert.equal(button.root.type, 'button'); 113 | assert.ok(button.refs.button); 114 | }); 115 | 116 | it('should be able to find multiple components', function() { 117 | var stub = createStub(); 118 | var tree = render(React.createElement(Application, { 119 | onClick: stub 120 | })); 121 | 122 | var buttons = tree.findAllComponent(Button); 123 | 124 | assert.equal(buttons[0].root.type, 'button'); 125 | assert.equal(buttons[1].root.type, 'button'); 126 | }); 127 | 128 | it('should be able to find an element from a component', function() { 129 | var stub = createStub(); 130 | var tree = render(React.createElement(Application, { 131 | onClick: stub 132 | })); 133 | 134 | var button = tree 135 | .findComponent(Button) 136 | .find(function(element) { 137 | return element.type === 'button'; 138 | }); 139 | 140 | assert.equal(button.type, 'button'); 141 | }); 142 | 143 | it('should be able to simulate an event on an element', function() { 144 | var stub = createStub(); 145 | var tree = render(React.createElement(Application, { 146 | onClick: stub 147 | })); 148 | 149 | tree.find(function(element) { 150 | return element.type === 'button'; 151 | }).simulate('click'); 152 | 153 | assert.ok(stub.called); 154 | }); 155 | }); 156 | --------------------------------------------------------------------------------