Skip to content

Commit

Permalink
Refactored example app's reducer structure for clarity. Updated initi…
Browse files Browse the repository at this point in the history
…alState to place example app's state under an object to help convey that it's just a potential slice of state.
  • Loading branch information
coryhouse committed May 13, 2016
1 parent adbd56b commit f9b93d1
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 55 deletions.
28 changes: 15 additions & 13 deletions src/components/FuelSavingsForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ class FuelSavingsForm extends React.Component {
}

onTimeframeChange(e) {
this.props.calculateFuelSavings(this.props.appState, 'milesDrivenTimeframe', e.target.value);
this.props.calculateFuelSavings(this.props.fuelSavings, 'milesDrivenTimeframe', e.target.value);
}

fuelSavingsKeypress(name, value) {
this.props.calculateFuelSavings(this.props.appState, name, value);
this.props.calculateFuelSavings(this.props.fuelSavings, name, value);
}

save() {
this.props.saveFuelSavings(this.props.appState);
this.props.saveFuelSavings(this.props.fuelSavings);
}

render() {
const {appState} = this.props;
const {fuelSavings} = this.props;

return (
<div>
Expand All @@ -33,20 +33,22 @@ class FuelSavingsForm extends React.Component {
<tbody>
<tr>
<td><label htmlFor="newMpg">New Vehicle MPG</label></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="newMpg" value={appState.newMpg}/></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="newMpg" value={fuelSavings.newMpg}/>
</td>
</tr>
<tr>
<td><label htmlFor="tradeMpg">Trade-in MPG</label></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="tradeMpg" value={appState.tradeMpg}/>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="tradeMpg" value={fuelSavings.tradeMpg}/>
</td>
</tr>
<tr>
<td><label htmlFor="newPpg">New Vehicle price per gallon</label></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="newPpg" value={appState.newPpg}/></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="newPpg" value={fuelSavings.newPpg}/>
</td>
</tr>
<tr>
<td><label htmlFor="tradePpg">Trade-in price per gallon</label></td>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="tradePpg" value={appState.tradePpg}/>
<td><FuelSavingsTextInput onChange={this.fuelSavingsKeypress} name="tradePpg" value={fuelSavings.tradePpg}/>
</td>
</tr>
<tr>
Expand All @@ -55,12 +57,12 @@ class FuelSavingsForm extends React.Component {
<FuelSavingsTextInput
onChange={this.fuelSavingsKeypress}
name="milesDriven"
value={appState.milesDriven}/>
value={fuelSavings.milesDriven}/>
miles per
<select
name="milesDrivenTimeframe"
onChange={this.onTimeframeChange}
value={appState.milesDrivenTimeframe}>
value={fuelSavings.milesDrivenTimeframe}>
<option value="week">Week</option>
<option value="month">Month</option>
<option value="year">Year</option>
Expand All @@ -69,14 +71,14 @@ class FuelSavingsForm extends React.Component {
</tr>
<tr>
<td><label>Date Modified</label></td>
<td>{appState.dateModified}</td>
<td>{fuelSavings.dateModified}</td>
</tr>
</tbody>
</table>

<hr/>

{appState.necessaryDataIsProvidedToCalculateSavings && <FuelSavingsResults savings={appState.savings}/>}
{fuelSavings.necessaryDataIsProvidedToCalculateSavings && <FuelSavingsResults savings={fuelSavings.savings}/>}
<input type="submit" value="Save" onClick={this.save}/>
</div>
);
Expand All @@ -86,7 +88,7 @@ class FuelSavingsForm extends React.Component {
FuelSavingsForm.propTypes = {
saveFuelSavings: PropTypes.func.isRequired,
calculateFuelSavings: PropTypes.func.isRequired,
appState: PropTypes.object.isRequired
fuelSavings: PropTypes.object.isRequired
};

export default FuelSavingsForm;
48 changes: 24 additions & 24 deletions src/components/FuelSavingsForm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('<FuelSavingsForm />', () => {
it('should contain <FuelSavingsTextInput /> components', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -30,27 +30,27 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);
const allInputs = wrapper.find(FuelSavingsTextInput);

expect(allInputs).to.be.length(5);
expect(allInputs.at(0).props().name).to.equal('newMpg');
expect(allInputs.at(0).props().value).to.equal(appState.newMpg);
expect(allInputs.at(0).props().value).to.equal(fuelSavings.newMpg);
expect(allInputs.at(1).props().name).to.equal('tradeMpg');
expect(allInputs.at(1).props().value).to.equal(appState.tradeMpg);
expect(allInputs.at(1).props().value).to.equal(fuelSavings.tradeMpg);
expect(allInputs.at(2).props().name).to.equal('newPpg');
expect(allInputs.at(2).props().value).to.equal(appState.newPpg);
expect(allInputs.at(2).props().value).to.equal(fuelSavings.newPpg);
expect(allInputs.at(3).props().name).to.equal('tradePpg');
expect(allInputs.at(3).props().value).to.equal(appState.tradePpg);
expect(allInputs.at(3).props().value).to.equal(fuelSavings.tradePpg);
expect(allInputs.at(4).props().name).to.equal('milesDriven');
expect(allInputs.at(4).props().value).to.equal(appState.milesDriven);
expect(allInputs.at(4).props().value).to.equal(fuelSavings.milesDriven);
});

it('should contain options to change miles driven timeframe', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -70,7 +70,7 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);
const expectedOption1 = '<option value="week">Week</option>';
const expectedOption2 = '<option value="month">Month</option>';
Expand All @@ -84,7 +84,7 @@ describe('<FuelSavingsForm />', () => {
it('should contain <FuelSavingsResults /> when necessary conditions are met', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -104,17 +104,17 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);
const expected = <FuelSavingsResults savings={appState.savings}/>;
const expected = <FuelSavingsResults savings={fuelSavings.savings}/>;

expect(wrapper.contains(expected)).to.be.true;
});

it('should not contain <FuelSavingsResults /> when necessary conditions are not met', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -134,17 +134,17 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);
const expected = <FuelSavingsResults savings={appState.savings}/>;
const expected = <FuelSavingsResults savings={fuelSavings.savings}/>;

expect(wrapper.contains(expected)).to.be.false;
});

it('should handle form submit', () => {
const saveFuelSavings = sinon.spy();
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -164,7 +164,7 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);

expect(saveFuelSavings.calledOnce).to.be.false;
Expand All @@ -175,7 +175,7 @@ describe('<FuelSavingsForm />', () => {
it('should submit appState', () => {
const saveFuelSavings = sinon.spy();
const calculateFuelSavings = () => {};
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -195,18 +195,18 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);

wrapper.find('input[type="submit"]').simulate('click');
expect(saveFuelSavings.args[0][0]).to.equal(appState);
expect(saveFuelSavings.args[0][0]).to.equal(fuelSavings);
});


it('should calculate fuel savings on text input change', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = sinon.spy();
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -226,7 +226,7 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);

expect(calculateFuelSavings.calledOnce).to.be.false;
Expand All @@ -237,7 +237,7 @@ describe('<FuelSavingsForm />', () => {
it('should calculate fuel savings on miles driven timeframe change', () => {
const saveFuelSavings = () => {};
const calculateFuelSavings = sinon.spy();
const appState = {
const fuelSavings = {
newMpg: 20,
tradeMpg: 10,
newPpg: 1.50,
Expand All @@ -257,7 +257,7 @@ describe('<FuelSavingsForm />', () => {
const wrapper = shallow(<FuelSavingsForm
saveFuelSavings={saveFuelSavings}
calculateFuelSavings={calculateFuelSavings}
appState={appState}
fuelSavings={fuelSavings}
/>);

expect(calculateFuelSavings.calledOnce).to.be.false;
Expand Down
6 changes: 3 additions & 3 deletions src/containers/FuelSavingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ export const FuelSavingsPage = (props) => {
<FuelSavingsForm
saveFuelSavings={props.actions.saveFuelSavings}
calculateFuelSavings={props.actions.calculateFuelSavings}
appState={props.appState}
fuelSavings={props.fuelSavings}
/>
);
};

FuelSavingsPage.propTypes = {
actions: PropTypes.object.isRequired,
appState: PropTypes.object.isRequired
fuelSavings: PropTypes.object.isRequired
};

function mapStateToProps(state) {
return {
appState: state.fuelSavingsAppState
fuelSavings: state.fuelSavings
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/containers/FuelSavingsPage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ describe('<FuelSavingsPage />', () => {
saveFuelSavings: () => { },
calculateFuelSavings: () => { }
};
const appState = {};
const wrapper = shallow(<FuelSavingsPage actions={actions} appState={appState}/>);
const fuelSavings = {};
const wrapper = shallow(<FuelSavingsPage actions={actions} fuelSavings={fuelSavings}/>);

expect(wrapper.find(FuelSavingsForm)).to.be.length(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import initialState from './initialState';
// create a copy of the state passed and set new values on the copy.
// Note that I'm using Object.assign to create a copy of current state
// and update values on the copy.
export default function fuelSavingsAppState(state = initialState.fuelSavingsAppState, action) {
export default function fuelSavingsReducer(state = initialState.fuelSavings, action) {
let newState;

switch (action.type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { expect } from 'chai';
import * as ActionTypes from '../constants/actionTypes';
import reducer from './fuelSavings';
import reducer from './fuelSavingsReducer';
import dateHelper from '../businessLogic/dateHelper';

describe('Reducers::FuelSavings', () => {
const getInitialSate = () => {
const getInitialState = () => {
return {
newMpg: '',
tradeMpg: '',
Expand Down Expand Up @@ -44,9 +44,9 @@ describe('Reducers::FuelSavings', () => {

it('should set initial state by default', () => {
const action = { type: 'unknown' };
const expected = getInitialSate();
const expected = getInitialState();

expect(reducer(undefined, action)).to.deep.equal(expected); // Notice use of deep because it's a nested object
expect(reducer(getInitialState(), action)).to.deep.equal(expected); // Notice use of deep because it's a nested object
// expect(reducer(undefined, action)).to.equal(expected); // Fails. Not deeply equal
});

Expand Down
4 changes: 2 additions & 2 deletions src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { combineReducers } from 'redux';
import fuelSavingsAppState from './fuelSavings';
import fuelSavings from './fuelSavingsReducer';

const rootReducer = combineReducers({
fuelSavingsAppState
fuelSavings
});

export default rootReducer;
2 changes: 1 addition & 1 deletion src/reducers/initialState.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default {
fuelSavingsAppState: {
fuelSavings: {
newMpg: '',
tradeMpg: '',
newPpg: '',
Expand Down
10 changes: 5 additions & 5 deletions src/store/store.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ describe('Store', () => {
displayResults: false,
dateModified: dateHelper.getFormattedDateTime(new Date()),
necessaryDataIsProvidedToCalculateSavings: true,
savings: calculator().calculateSavings(store.getState().fuelSavingsAppState)
savings: calculator().calculateSavings(store.getState().fuelSavings)
};

expect(actual.fuelSavingsAppState).to.deep.equal(expected);
expect(actual.fuelSavings).to.deep.equal(expected);
});

it('should not display results when necessary data is not provided', () => {
Expand Down Expand Up @@ -67,7 +67,7 @@ describe('Store', () => {
};


expect(actual.fuelSavingsAppState).to.deep.equal(expected);
expect(actual.fuelSavings).to.deep.equal(expected);
});


Expand All @@ -94,7 +94,7 @@ describe('Store', () => {
];
actions.forEach(action => store.dispatch(action));

const lastGoodSavings = calculator().calculateSavings(store.getState().fuelSavingsAppState);
const lastGoodSavings = calculator().calculateSavings(store.getState().fuelSavings);

const moreActions = [
{ type: ActionTypes.CALCULATE_FUEL_SAVINGS, settings: store.getState(), fieldName: 'tradePpg', value: 0 },
Expand All @@ -119,6 +119,6 @@ describe('Store', () => {
savings: lastGoodSavings
};

expect(actual.fuelSavingsAppState).to.deep.equal(expected);
expect(actual.fuelSavings).to.deep.equal(expected);
});
});

0 comments on commit f9b93d1

Please sign in to comment.