UNPKG

omniscient

Version:

A library providing an abstraction for React components for passing the same data structure through the entire component flow using cursors and immutable data structures.

139 lines (118 loc) 4 kB
const Immutable = require('immutable'); const immstruct = require('immstruct'); const ReactDOM = require('react-dom'); const component = require('../'); const React = require('react'); describe('component render test', () => { test('should only re-render components that depend on changed data, but call shouldComponentUpdate for all', done => { var FIRST = 0, SECOND = 1; var structure = immstruct({ items: [{ id: FIRST }, { id: SECOND }] }); var calls = { render: {}, shouldComponentUpdate: {} }; calls.render[FIRST] = 0; calls.render[SECOND] = 0; calls.shouldComponentUpdate[FIRST] = 0; calls.shouldComponentUpdate[SECOND] = 0; var mixins = [ { // 5 shouldComponentUpdate: function() { var id = this.props.cursor.get('id'); calls.shouldComponentUpdate[id]++; return component.shouldComponentUpdate.apply(this, arguments); }, // 7 componentDidUpdate: function() { expect(calls.shouldComponentUpdate[FIRST]).toBe(1); expect(calls.shouldComponentUpdate[SECOND]).toBe(1); expect(calls.render[FIRST]).toBe(2); expect(calls.render[SECOND]).toBe(1); done(); } } ]; var Item = component('Item', mixins, function(props) { // 2 // 6 calls.render[props.cursor.toJS().id]++; return React.createElement('li', {}, ''); }); var List = component('List', function(props) { return React.createElement( 'ul', {}, props.cursor.toArray().map(function(item, i) { return Item('component-' + i, { cursor: item }); }) ); }); var div = document.createElement('div'); ReactDOM.render(List({ cursor: structure.cursor('items') }), div); // 1 structure.on('swap', function() { ReactDOM.render(List({ cursor: structure.cursor('items') }), div); // 4 }); structure.cursor().update('items', function(items) { return items.set(FIRST, Immutable.Map({ id: FIRST, changed: true })); // 3 }); }); test('should handle updates that mutate owners state', () => { const root = document.createElement('div'); document.body.appendChild(root); var click = function(node) { var event = new window.Event('click', { bubbles: true, cancelable: false }); node.dispatchEvent(event); }; var structure = immstruct({ items: [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }] }); var List = component('List', function(props) { var onRemove = function(item) { props.items.remove(props.items.indexOf(item)); }; return React.createElement( 'ul', {}, props.items.toArray().map(function(item) { return Item({ item: item, key: 'item-' + item.get('id'), statics: { onRemove: onRemove } }); }) ); }); var Item = component('Item', function(props) { return React.createElement( 'li', { className: props.item.get('isSelected') ? 'selected' : '' }, React.createElement( 'button', { id: 'item-' + props.item.get('id'), onClick: function() { props.statics.onRemove(props.item); } }, props.item.get('id') ) ); }); var render = function() { ReactDOM.render(List({ items: structure.cursor('items') }), root); }; structure.on('swap', render); render(); click(root.querySelector('button#item-1')); expect(root.querySelectorAll('li').length).toBe(3); expect(root.querySelectorAll('#item-1').length).toBe(0); click(root.querySelector('button#item-0')); expect(root.querySelectorAll('li').length).toBe(2); expect(root.querySelectorAll('button#item-1').length).toBe(0); expect(root.querySelectorAll('button#item-0').length).toBe(0); }); });