UNPKG

react-causality-redux

Version:
450 lines (385 loc) 16.3 kB
/* eslint-disable react/no-multi-comp */ /* eslint-disable react/jsx-sort-prop-types */ import assert from 'assert' import React from 'react' import CausalityRedux from 'causality-redux' import {Provider} from 'react-redux' import { mount } from 'enzyme' import '../lib/react-causality-redux.js' let counterPartitionState const COUNTER_STATE = 'Counter' const reduxCounter = { partitionName: COUNTER_STATE, defaultState: {counter: 0, counter3: 0}, uiServiceFunctions: { onIncrement: () => (counterPartitionState.counter++), onDecrement: () => (counterPartitionState.counter--), onIncrement3: () => (counterPartitionState.counter3++) } } let editPartitionState const FIELD_STATE = 'FIELD_STATE' const reduxField = { partitionName: FIELD_STATE, defaultState: {fieldValue: 'abcd'}, uiServiceFunctions: { onChangeField: (arg) => { var x = /^[a-zA-Z\s]*/.exec(arg) let fieldValue = '' if (x !== null) { fieldValue = x[0] } editPartitionState.fieldValue = fieldValue } } } const store = CausalityRedux.createStore([reduxCounter, reduxField]) const counterStore = store[COUNTER_STATE] counterPartitionState = counterStore.partitionState const editStore = store[FIELD_STATE] editPartitionState = editStore.partitionState describe('CausalityRedux createStore', function () { it('CausalityRedux.store should exist', function () { assert(typeof store !== 'undefined') }) it('CausalityRedux.connectChangersAndStateToProps should be a function.', function () { assert(typeof CausalityRedux.connectChangersAndStateToProps === 'function') }) it('CausalityRedux.connectChangersToProps should be a function.', function () { assert(typeof CausalityRedux.connectChangersToProps === 'function') }) it('CausalityRedux.connectStateToProps should be a function.', function () { assert(typeof CausalityRedux.connectStateToProps === 'function') }) it('CausalityRedux.establishControllerConnections should be a function.', function () { assert(typeof CausalityRedux.establishControllerConnections === 'function') }) }) const CounterForm = ({onIncrement, onDecrement, onIncrement3, counter, counter3}) => <div className='counter-form-button-container'> <div id='counter-text' >{counter}</div> <div id='counter-text3' >{counter3}</div> <button id='onIncrement' onClick={e => onIncrement()}>Up</button> <button id='onDecrement' onClick={e => onDecrement()}>Down</button> <button id='onIncrement3' onClick={e => onIncrement3()}>Up</button> </div> const CounterFormCausalityRedux = CausalityRedux.connectChangersAndStateToProps(CounterForm, COUNTER_STATE, ['onIncrement', 'onDecrement', 'onIncrement3'], ['counter', 'counter3']) const CounterForm2 = ({onIncrement}) => <button id='onIncrement2' onClick={e => onIncrement()}>Up</button> const CounterForm2CausalityRedux = CausalityRedux.connectChangersToProps(CounterForm2, COUNTER_STATE, ['onIncrement']) const CounterForm3 = ({counter}) => <div id='counter-text2' >{counter}</div> const CounterForm3CausalityRedux = CausalityRedux.connectStateToProps(CounterForm3, COUNTER_STATE, ['counter']) const EditField = ({fieldValue, onChangeField}) => <input id='EditField' type='text' name='ID' required='required' value={fieldValue} placeholder='Name' onChange={e => onChangeField(e.target.value)} /> const EditFieldCausalityRedux = CausalityRedux.connectChangersAndStateToProps(EditField, FIELD_STATE, ['onChangeField'], ['fieldValue']) const waitTime = 2000 let intervalID // // React rendering is asynchronous. Components must be validated asynchronously. // const handleReactAsync = (done, startTime, waitTime, callbackCheck) => { // The callback checks that the conditions for success have been met if (callbackCheck()) { clearInterval(intervalID) done() // Timeout means failure. } else if (new Date() - startTime > waitTime) { clearInterval(intervalID) done(new Error('Timeout')) } } const handleReactAsyncStart = (done, waitTime, callbackCheck) => { intervalID = setInterval(handleReactAsync, 10, done, new Date(), waitTime, callbackCheck) } export const nodeExists = selector => appMount.find(selector).exists() export const nodeString = selector => appMount.find(selector).text() export const nodeValue = selector => appMount.find(selector).get(0).value export const simulateClick = selector => appMount.find(selector).first().simulate('click') export const simulateInput = (selector, value) => appMount.find(selector).first().simulate('change', {target: {value}}) export const testCauseAndEffectWithExists = (causeSelector, effectSelector, done) => { simulateClick(causeSelector) handleReactAsyncStart(done, waitTime, () => nodeExists(effectSelector) ) } export const testCauseAndEffectWithNotExists = (causeSelector, effectSelector, done) => { simulateClick(causeSelector) handleReactAsyncStart(done, waitTime, () => !nodeExists(effectSelector) ) } export const testCauseAndEffectWithHtmlString = (causeSelector, effectSelector, expectedHtmlString, done) => { simulateClick(causeSelector) handleReactAsyncStart(done, waitTime, () => nodeString(effectSelector) === expectedHtmlString ) } export const testCauseAndEffectWithTextField = (causeSelector, inputValue, expectedValue, done) => { simulateInput(causeSelector, inputValue) handleReactAsyncStart(done, waitTime, () => nodeValue(causeSelector) === expectedValue ) } const CounterFormValue = ({ counter }) => <div id='counterformvalue'> {`Counter Display: ${counter}`} </div> const CounterForm4 = ({ increment, decrement, counter, CounterFormValue }) => <div> <div id='counter-text4' >{`The current counter is ${counter}.`}</div> <CounterFormValue /> <button id='onIncrement4' label='Up' onClick={increment} /> <button id='onDecrement4' label='Down' onClick={decrement} /> </div> let defaultState = { counter: 0 } let uiServiceFunctions = { increment: () => ++partitionState2.counter, decrement: () => --partitionState2.counter } const counterFormPartition4 = 'counterFormPartition4' let controllerUIConnections = [ [ CounterFormValue, // React Component to wrap with redux connect counterFormPartition4, [], // Function keys that you want passed into the props of the react component. ['counter'], // Partition keys that you want passed into the props of the react component. 'CounterFormValue' // Name of the react component string form ], [ CounterForm4, // Wrapped component counterFormPartition4, ['increment', 'decrement'], ['counter', 'CounterFormValue'], 'CounterForm4' ] ] let ret = CausalityRedux.establishControllerConnections({ module, partition: { partitionName: counterFormPartition4, defaultState, uiServiceFunctions }, controllerUIConnections }) const partitionState2 = ret.partitionState const setState2 = ret.setState const getState2 = ret.getState const partitionStore2 = ret.partitionStore const CounterForm5 = ({ increment, decrement, counter }) => <div> <div id='counter-text5' >{`The current counter is ${counter}.`}</div> <button id='onIncrement5' label='Up' onClick={increment} /> <button id='onDecrement5' label='Down' onClick={decrement} /> </div> defaultState = { counter: 0 } uiServiceFunctions = { increment: () => ++partitionState5.counter, decrement: () => --partitionState5.counter } const counterFormPartition5 = 'counterFormPartition5' ret = CausalityRedux.establishControllerConnections({ module, partition: { partitionName: counterFormPartition5, defaultState, uiServiceFunctions }, uiComponent: CounterForm5, uiComponentName: 'CounterForm5' }) const UiComponent5 = ret.wrappedComponents.CounterForm5 const partitionState5 = ret.partitionState const setState5 = ret.setState const getState5 = ret.getState const partitionStore5 = ret.partitionStore const CounterFormValue2 = ({ counter }) => <div id='counterformvalue6'> {`Counter Display: ${counter}`} </div> controllerUIConnections = [ [ CounterFormValue2, // React Component to wrap with redux connect counterFormPartition4, [], // Function keys that you want passed into the props of the react component. ['counter'], // Partition keys that you want passed into the props of the react component. 'CounterFormValue2' // Name of the react component string form ] ] ret = CausalityRedux.establishControllerConnections({ module, controllerUIConnections }) const UiComponent6 = ret.wrappedComponents.CounterFormValue2 const partitionState6 = ret.partitionState const setState6 = ret.setState const getState6 = ret.getState const partitionStore6 = ret.partitionStore const appMount = mount( <Provider store={CausalityRedux.store}> <div> <CounterFormCausalityRedux /> <EditFieldCausalityRedux /> <CounterForm2CausalityRedux /> <CounterForm3CausalityRedux /> <partitionState2.CounterForm4 /> <UiComponent5 /> <UiComponent6 /> </div> </Provider> ) describe('Operations CounterForm and CounterForm3', function (done) { // // Demonstrate that onIncrement works and updates the state value counter in CounterForm and CounterForm3. // This also verifies connectChangersAndStateToProps and connectStateToProps. // // Click on the increment button it('increment cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement', '#counter-text', '1', done) }) it('Increment button should increment counter in the COUNTER_STATE partition.', function () { assert(counterStore.getState().counter === 1) }) it('Counter displayed in component CounterForm3 should have updated.', function () { assert(nodeString('#counter-text2') === '1') }) // // Demonstrate that onDecrement works and updates the state value counter in CounterForm and CounterForm3. // This also verifies connectChangersAndStateToProps and connectStateToProps. // it('decrement cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onDecrement', '#counter-text', '0', done) }) it('Decrement button should decrement counter in the COUNTER_STATE partition.', function () { assert(counterStore.getState().counter === 0) }) it('Counter displayed in component CounterForm3 should have updated.', function () { assert(nodeString('#counter-text2') === '0') }) // // This updates the COUNTER_STATE value counter3 and proves CounterForm and CounterForm3 do not render since they do not listen to its changes // but are connected to the state partition COUNTER_STATE. // it('Try async click on counter increment button3', function (done) { testCauseAndEffectWithHtmlString('#onIncrement3', '#counter-text3', '1', done) }) it('Increment3 button should increment counter3 in the COUNTER_STATE partition.', function () { assert(counterStore.getState().counter3 === 1) }) // // Demonstrate that onIncrement works and updates the state value counter in CounterForm and CounterForm3 with just connectChangersToProps. // it('increment cause and effect 2 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement2', '#counter-text', '1', done) }) it('Increment button should increment counter in the COUNTER_STATE partition to exercise connectChangersToProps.', function () { assert(counterStore.getState().counter === 1) }) it('Counter displayed in component CounterForm3 should have updated.', function () { assert(nodeString('#counter-text2') === '1') }) }) describe('EditField corrected by controller logic.', function () { it('Try onchange on the input field.', function (done) { testCauseAndEffectWithTextField('#EditField', 'abcd2', 'abcd', done) }) it('Verify that fieldValue in the FIELD_STATE partition is "abcd".', function () { assert(editStore.getState().fieldValue === 'abcd') }) it('Verify that the input field is "abcd".', function () { assert(nodeValue('#EditField') === 'abcd') }) }) // // Test establishControllerConnections with one component. // describe('Test establishControllerConnections with one component.', function () { it('UiComponent5 is defined - validated.', function () { assert(UiComponent5 !== undefined) }) it('partitionState5 is defined - validated.', function () { assert(partitionState5 !== undefined) }) it('setState5 is defined - validated.', function () { assert(setState5 !== undefined) }) it('getState5 is defined - validated.', function () { assert(getState5 !== undefined) }) it('partitionStore5 is defined - validated.', function () { assert(partitionStore5 !== undefined) }) // Click on the increment button it('increment cause and effect - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement5', '#counter-text5', 'The current counter is 1.', done) }) // Click on the decrement button it('decrement cause and effect - validated.', function (done) { testCauseAndEffectWithHtmlString('#onDecrement5', '#counter-text5', 'The current counter is 0.', done) }) }) // // Test establishControllerConnections with multiple components. // describe('Test establishControllerConnections with multiple components.', function () { it('partitionState2 is defined - validated.', function () { assert(partitionState2 !== undefined) }) it('setState2 is defined - validated.', function () { assert(setState2 !== undefined) }) it('getState2 is defined - validated.', function () { assert(getState2 !== undefined) }) it('partitionStore2 is defined - validated.', function () { assert(partitionStore2 !== undefined) }) // Click on the increment button it('increment cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement4', '#counter-text4', 'The current counter is 1.', done) }) // Click on the increment button it('increment cause and effect 2 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement4', '#counterformvalue', 'Counter Display: 2', done) }) // Click on the decrement button it('decrement cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onDecrement4', '#counter-text4', 'The current counter is 1.', done) }) // Click on the decrement button it('decrement cause and effect 2 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onDecrement4', '#counterformvalue', 'Counter Display: 0', done) }) }) // // Test establishControllerConnections with component and no partition definition // describe('Test establishControllerConnections with component and no partition definition.', function () { it('UiComponent6 is not undefined - validated.', function () { assert(UiComponent6 !== undefined) }) it('partitionState6 is undefined - validated.', function () { assert(partitionState6 === undefined) }) it('setState6 is undefined - validated.', function () { assert(setState6 === undefined) }) it('getState6 is undefined - validated.', function () { assert(getState6 === undefined) }) it('partitionStore6 is undefined - validated.', function () { assert(partitionStore6 === undefined) }) // Click on the increment button it('increment cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onIncrement4', '#counterformvalue6', 'Counter Display: 1', done) }) // Click on the decrement button it('decrement cause and effect 1 - validated.', function (done) { testCauseAndEffectWithHtmlString('#onDecrement4', '#counterformvalue6', 'Counter Display: 0', done) }) })