UNPKG

thundercats-react

Version:

Thundercats addon for use with React

399 lines (355 loc) 10.1 kB
/* eslint-disable no-unused-expressions, react/display-name */ /* eslint-disable react/no-multi-comp */ import Rx, { Observable } from 'rx'; import { Actions, dehydrate, Cat, Store } from 'thundercats'; import chai, { expect, assert } from 'chai'; import { React, createActions, createClass, ReactTestUtils, unmountComp } from './utils'; import { createContainer, render$, renderToString$ } from '../src'; import { renderToObs$ } from '../src/Render'; Rx.config.longStackSupport = true; chai.should(); describe('renderToObs$', function() { it('should report errors', () => { renderToObs$().subscribe( () => {}, err => { console.log(err.message); assert(err, 'did not report error'); assert( (/invalid component element/i).test(err.message), 'did not throw expected error' ); } ); }); }); describe('renderToString$', function() { let cat; this.timeout(6000); beforeEach(() => { cat = Cat()(); }); it('should return an observable', () => { let TestComp = createClass({}); let TestElement = React.createElement(TestComp); let renderObs = renderToString$(cat, TestElement); renderObs.subscribe.should.be.a('function'); }); describe('fetching', () => { let payload, wrappedPayload, TestComp; beforeEach(() => { let CatActions = createActions(); let CatStore = createStore(); payload = { name: 'foo' }; wrappedPayload = { value: payload }; cat.register(CatActions); cat.register(CatStore, null, cat); }); it('should initiate fetcher registration', (done) => { TestComp = createContainer( { store: 'catStore', fetchAction: 'catActions.doAction', getPayload: () => wrappedPayload }, createClass() ); renderToString$(cat, React.createElement(TestComp)) .subscribe(({ fetchMap }) => { expect(fetchMap).to.exist; fetchMap.size.should.equal(1); const fetchContext = fetchMap.get('catActions.doAction'); expect(fetchContext).to.exist; fetchContext.should.be.an('object'); fetchContext.should.include.keys( 'name', 'payload', 'action', 'store' ); done(); }); }); it('should be ok with empty payload', (done) => { TestComp = createContainer( { store: 'CatStore', fetchAction: 'catActions.doAction', getPayload: () => ({}) }, createClass() ); renderToString$(cat, React.createElement(TestComp)) .subscribe(({ fetchMap }) => { const fetchContext = fetchMap.get('catActions.doAction'); expect(fetchContext).to.exist; fetchContext.should.include.keys( 'name', 'payload', 'action', 'store' ); fetchContext.payload.should.deep.equal({}); done(); }); }); }); describe('observable', () => { let element; beforeEach(() => { let CatActions = createActions(); let CatStore = createStore(); let Comp = createContainer( { store: 'CatStore', fetchAction: 'catActions.doAction', getPayload: () => ({}) }, createClass() ); element = React.createElement(Comp); cat.register(CatActions); cat.register(CatStore, null, cat); }); it('should return markup', done => { renderToString$(cat, element) .subscribe(({ markup })=> { assert.equal( typeof markup, 'string', 'markup returned is not a string' ); done(); }); }); it('should pre-fetch data', done => { const felineElement = React.createElement(createContainer( { store: 'felineStore', fetchAction: 'felineActions.doAction', getPayload: () => ({}) }, createClass({ displayName: 'Feline', render() { return element; } }) )); const FelineActions = Actions({ refs: { displayName: 'FelineActions' }, doAction() { return Observable.just({ replace: { fur: 'sneeze' } }).delay(900); } }); const CatActions = Actions({ refs: { displayName: 'catActions' }, doAction() { return Observable.just({ set: { foo: 'baz' } }).delay(500); } }); const FelineStore = Store({ refs: { value: { pet: 'pur' }, displayName: 'FelineStore' }, init({ instance: store, args: [cat] }) { const actions = cat.getActions('FelineActions'); store.register(actions.doAction); } }); const CatStore = Store({ refs: { value: { foo: 'bar' }, displayName: 'CatStore' }, init({ instance: store, args: [cat] }) { const actions = cat.getActions('catActions'); store.register(actions.doAction); } }); const cat = Cat()(); cat.register(CatActions); cat.register(FelineActions); cat.register(CatStore, null, cat); cat.register(FelineStore, null, cat); renderToString$(cat, felineElement) .flatMap( dehydrate(cat), ) .doOnNext(({ CatStore, FelineStore })=> { assert( !FelineStore.pur, 'felineStore did not update' ); assert.equal( FelineStore.fur, 'sneeze', 'feline store did not fetch' ); assert.equal( CatStore.foo, 'baz', 'foo did not equal baz' ); }) .subscribe( () => {}, done, done ); }); it('should prevent infinite loops', done => { const element = React.createElement(createContainer( { actions: ['catActions'], store: 'catStore', fetchAction: 'catActions.doAction', getPayload: () => ({}) }, createClass({ displayName: 'Test', propTypes: { catActions: React.PropTypes.object }, componentWillMount() { this.props.catActions.doThis(); }, render() { return React.createElement('h1', null, 'hello world'); } }) )); const CatActions = Actions({ refs: { displayName: 'catActions' }, doAction() { return Observable.just({ set: { foo: 'baz' } }).delay(500); }, doThis() { return { set: { qux: 'quo' } }; } }); const CatStore = Store({ refs: { value: { foo: 'bar' }, displayName: 'CatStore' }, init({ instance: store, args: [cat] }) { const actions = cat.getActions('catActions'); store.register(actions.doAction); store.register(actions.doThis); } }); const cat = Cat()(); cat.register(CatActions); cat.register(CatStore, null, cat); renderToString$(cat, element) .flatMap( dehydrate(cat), ) .doOnNext(({ CatStore })=> { assert.equal( CatStore.foo, 'baz', 'foo did not equal baz' ); assert.isNotOk(CatStore.qux); }) .subscribe( () => {}, done, done ); }); it('should error on fetch errors', (done) => { renderToString$(cat, 'not the momma') .subscribe( () => {}, err => { assert(err instanceof Error, 'err is not instance of Error'); done(); } ); }); it('should complete', (done) => { renderToString$(cat, element) .subscribe( () => {}, () => {}, () => done() ); }); }); }); describe('render', function() { let cat, Comp, element; beforeEach(() => { let CatActions = createActions(); let CatStore = createStore(); Comp = createContainer( { store: 'CatStore', fetchAction: 'catActions.doAction', getPayload: () => ({}) }, createClass() ); element = React.createElement(Comp); cat = Cat()(); cat.register(CatActions); cat.register(CatStore, null, cat); }); it('should return an observable', () => { let divContainer = document.createElement('div'); let renderObserable = render$(cat, element, divContainer); expect(renderObserable).to.exist; renderObserable.subscribe.should.be.a('function'); }); describe('observable', () => { let divContainer; beforeEach(() => { divContainer = document.createElement('div'); }); afterEach(() => { unmountComp(divContainer); }); it('should return react instance', (done) => { let renderObserable = render$(cat, element, divContainer); expect(renderObserable).to.exist; renderObserable .first() .subscribe(function(inst) { expect(inst).to.exist; ReactTestUtils.isCompositeComponent(inst).should.be.true; done(); }); }); it('should return error', (done) => { let renderObserable = render$(cat, 'foo', divContainer); expect(renderObserable).to.exist; renderObserable .subscribeOnError(err => { expect(err).to.exist; err.should.be.an.instanceOf(Error); done(); }); }); }); }); function createStore(initValue = null) { return Store({ refs: { value: initValue }}) .refs({ displayName: 'CatStore' }) .init(({ instance, args }) => { const [ cat ] = args; let catActions = cat.getActions('CatActions'); instance.register( catActions.doAction.delay(500).map(() => ({ replace: {}})) ); }); }