Skip to content

Commit 75e90b1

Browse files
committed
2 parents fde5f3c + f4b661b commit 75e90b1

File tree

10 files changed

+117
-80
lines changed

10 files changed

+117
-80
lines changed

app/scripts/actions.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@
99
* Balances
1010
*/
1111
const SET_BALANCES = 'SET_BALANCES';
12-
const SET_TRANSACTION_FIELD = 'SET_TRANSACTION_FIELD';
1312

1413
const setBalances = (balances) =>
1514
({type: SET_BALANCES, balances});
1615

1716
const balanceActions = {
1817
withdraw: () => ({type: 'TRANSACTION_START', value: 'WITHDRAW'}),
1918
deposit: () => ({type: 'TRANSACTION_START', value: 'DEPOSIT'}),
20-
amount: (value) => ({type: 'SET_TRANSACTION_FIELD', value, field: 'amount'}),
21-
account: (value) => ({type: 'SET_TRANSACTION_FIELD', value, field: 'account'})
19+
amount: (value) => ({type: 'AMOUNT_CHANGED', value, field: 'amount'}),
20+
account: (value) => ({type: 'ACCOUNT_CHANGED', value, field: 'account'})
2221
};
2322

2423
/**
@@ -63,5 +62,5 @@ const ADD_TRANSACTION = 'ADD_TRANSACTION';
6362
const addTransaction = (transaction) =>
6463
({type: ADD_TRANSACTION, transaction});
6564

66-
const newTransaction = (account, amount, factor) =>
67-
({account, amount, factor, type: NEW_TRANSACTION});
65+
const newTransaction = (type, account, amount, factor) =>
66+
({account, amount: factor * amount, type});

app/scripts/app.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,6 @@
66
*/
77
'use strict';
88
(function() {
9-
// Start configuration step here
10-
// 1) Check logged in status
11-
// 2) Force log-in
12-
// 3) Use log-in token to get dashboard set-up information
13-
14-
/* Action Items:
15-
*
16-
* 1) Data (stocks, accounts, transactions, routing?)
17-
* 2) Tool to build transaction history
18-
* 3) Tool to build stock history
19-
20-
* */
219

2210
const {Observable} = Rx;
2311
const {createStore} = Redux;
@@ -35,14 +23,14 @@
3523
};
3624

3725
const middlewareFactories = [
38-
initializeEpic,
26+
initializeEpic(accountsDB),
3927
searchEpic,
4028
messageEpic,
4129
userEpic,
4230
interestEpic,
4331
transactionEpic,
4432
transactionLogEpic,
45-
loggingEpic
33+
loggingEpic()
4634
];
4735

4836
// Builds the global store with reducers and an initial state

app/scripts/components/message.component.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Paul Daniels
55
* @author Luis Atencio
66
*/
7-
(function(global) {
7+
(function() {
88

99
const Message = (props) => {
1010
const {Alert} = ReactBootstrap;

app/scripts/epics/interest.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
* @author Luis Atencio
66
*/
77

8-
const computeInterest = p => 0.1 / 365 * p;
8+
const computeInterest = p => 1 / 10 / 365 * p;
99

1010
// Processes interest payments
11-
function interestEpic(action$, store) {
12-
return Rx.Observable.interval(15000)
13-
.map(() => store.getState())
14-
.pluck('accounts')
15-
.map(
16-
({savings}) => ({
17-
type: 'DEPOSIT',
18-
account: 'savings',
19-
amount: computeInterest(savings)
20-
})
21-
);
11+
function interestEpic(action$, store, scheduler) {
12+
return Rx.Observable.interval(15 * 1000, scheduler)
13+
.map(() => store.getState())
14+
.pluck('accounts')
15+
.map(
16+
({savings}) => ({
17+
type: 'DEPOSIT',
18+
account: 'savings',
19+
amount: computeInterest(savings)
20+
})
21+
);
2222
}

app/scripts/epics/logging.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
* @author Paul Daniels
55
* @author Luis Atencio
66
*/
7-
const loggingEpic = (action$) => action$
7+
const loggingEpic = (console = window.console) => (action$) => action$
88
.do(
99
action => {
10-
console.log(`Dispatch [${action.type}]`, action)
10+
console.log(`Dispatching [${action.type}]`, action)
1111
},
1212
err => console.error(err)
1313
)

app/scripts/epics/transaction.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,22 @@ function transactionLogEpic(action$, store) {
5555
);
5656
}
5757

58-
const getAccounts = () => Rx.Observable.fromPromise(accountsDB.get('accounts'));
58+
const getAccounts = (db) => Rx.Observable.from(db.get('accounts'));
5959

60-
function initializeEpic() {
61-
return getAccounts()
62-
.catch(err => {
63-
const defaults = {_id: 'accounts', checking: 100, savings: 100};
64-
return accountsDB.put(defaults)
65-
.then(() => defaults);
66-
})
67-
.map(accounts => {
68-
const {checking, savings} = accounts;
69-
return setBalances({checking, savings});
70-
});
60+
function initializeEpic(db) {
61+
return function() {
62+
return getAccounts(db)
63+
// If there is an error getting the accounts just start with some money to play with
64+
.catch(err => {
65+
const defaults = {_id: 'accounts', checking: 100, savings: 100};
66+
return Rx.Observable.from(db.put(defaults))
67+
.mapTo(defaults);
68+
})
69+
.map(accounts => {
70+
const {checking, savings} = accounts;
71+
return setBalances({checking, savings});
72+
});
73+
}
7174
}
7275

7376
class Transaction {

app/scripts/util/createMiddleware.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99

1010
// A custom utility operator for only accepting messages
1111
// of a certain type
12-
/**
13-
* @param types {string[]}
14-
* @returns {function(*): boolean}
15-
*/
1612
Rx.Observable.prototype.ofType = function (...types) {
1713
const len = types.length;
1814
return this.filter(({type}) => {

app/scripts/util/searchEngine.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class SearchQuery extends Rx.Observable {
1515
const { query, options, _subject } = this;
1616

1717
// Degenerate case, if there is no data then simply return immediately
18-
if (query.length == 0)
18+
if (query.length === 0)
1919
return Rx.Observable.of([]).subscribe(observer);
2020

2121
//The options for the search

test/index.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818
<!-- Sources -->
1919
<script src="../app/scripts/util/createMiddleware.js"></script>
2020
<script src="../app/scripts/actions.js"></script>
21-
<script src="../app/scripts/epics.js"></script>
21+
<script src="../app/scripts/epics/user.js"></script>
22+
<script src="../app/scripts/epics/logging.js"></script>
23+
<script src="../app/scripts/epics/message.js"></script>
24+
<script src="../app/scripts/epics/search.js"></script>
25+
<script src="../app/scripts/epics/transaction.js"></script>
26+
<script src="../app/scripts/epics/interest.js"></script>
2227

2328
<!-- Scripts -->
2429
<script src="test.balance.js"></script>

test/test.balance.js

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
*/
77
const expect = chai.expect;
88

9-
// function assertDeepEqual(actual, expected) { //#A
10-
// expect(actual).to.deep.equal(expected);
11-
// }
9+
function assertDeepEqual(actual, expected) { //#A
10+
expect(actual).to.deep.equal(expected);
11+
}
1212

1313
function stringify(x) {
1414
return JSON.stringify(x, function (key, value) {
@@ -62,7 +62,7 @@ function frames(n = 1, unit = '-') { //#A
6262
unit + frames(n - 1, unit);
6363
}
6464

65-
65+
// Example unit tests, to see, open the index.html file from the same directory in your web browser
6666
describe('Balances', () => {
6767

6868
let scheduler;
@@ -79,26 +79,19 @@ describe('Balances', () => {
7979
it('should zero the balances on error', () => {
8080

8181
const fakeDB = {
82-
accounts: {
83-
get: () => scheduler.createColdObservable('--#')
84-
}
82+
get: () => scheduler.createColdObservable('--#'),
83+
put: () => scheduler.createColdObservable('-x')
8584
};
8685

8786
const mappings = {
88-
// The beginning balance
89-
a: {checking: 10, savings: 20},
90-
// Signal the update
91-
b: refreshBalances(),
9287
// Expect the balance to be set
93-
c: setBalances({checking: 0, savings: 0})
88+
a: setBalances({checking: 100, savings: 100})
9489
};
9590

96-
const input$ = scheduler
97-
.createHotObservable('---b', mappings);
98-
const expected$ = '--c--c';
91+
const expected$ = '---a';
9992

10093
scheduler.expectObservable(
101-
initializeEpic(fakeDB)(input$)
94+
initializeEpic(fakeDB)(Rx.Observable.empty())
10295
).toBe(expected$, mappings);
10396

10497
scheduler.flush();
@@ -107,7 +100,7 @@ describe('Balances', () => {
107100

108101
describe('#userEpic', () => {
109102

110-
it('should emit a new transaction', () => {
103+
it('should emit a new withdraw transaction', () => {
111104

112105
const actionMapping = {
113106
a: balanceActions.account('checking'),
@@ -116,7 +109,7 @@ describe('Balances', () => {
116109
};
117110

118111
const expectMapping = {
119-
d: newTransaction('checking', 10, -1)
112+
d: newTransaction('WITHDRAW', 'checking', 10, -1)
120113
};
121114

122115
const action$ = scheduler.createHotObservable('-a-b-c', actionMapping);
@@ -132,34 +125,87 @@ describe('Balances', () => {
132125
scheduler.flush();
133126
});
134127

135-
it('should use the latest balance', () => {
128+
it('should emit a new deposit transaction', () => {
129+
const actionMapping = {
130+
a: balanceActions.account('savings'),
131+
b: balanceActions.amount(10),
132+
c: balanceActions.deposit()
133+
};
134+
135+
const expectMapping = {
136+
d: newTransaction('DEPOSIT', 'savings', 10, 1)
137+
};
138+
139+
const action$ = scheduler.createHotObservable('-a-b-c', actionMapping);
140+
141+
scheduler.expectObservable(
142+
userEpic(action$)
143+
).toBe(
144+
'-----d',
145+
expectMapping
146+
);
136147

148+
scheduler.flush();
137149
});
138150
});
139151

140152
describe('#interestEpic', () => {
141153
it('should accumulate interest', () => {
142154

143155
const expectMapping = {
144-
a: newTransaction('savings', (1), 1)
156+
// Rounding error
157+
a: newTransaction('DEPOSIT', 'savings', 1.0000000000000002, 1)
145158
};
146159

147-
const storeMapping = {
148-
a: 365 * 10
160+
const stubStore = {
161+
getState() {
162+
return {
163+
accounts: {
164+
savings: 365 * 10
165+
}
166+
};
167+
}
149168
};
150169

151-
const balance$ = scheduler.createColdObservable('---a', storeMapping);
152-
const trigger$ = scheduler.createHotObservable('---a');
153-
154170
scheduler.expectObservable(
155-
computeInterest(trigger$, balance$)
171+
interestEpic(Rx.Observable.empty(), stubStore, scheduler)
156172
).toBe(
157-
'------a',
173+
frames(15 * 100) + 'a',
158174
expectMapping
159175
);
176+
});
177+
});
178+
179+
describe('#loggingEpic', () => {
180+
it('should log dispatch actions', () => {
181+
182+
const actionsMap = {
183+
a: balanceActions.withdraw(),
184+
b: balanceActions.account('savings'),
185+
c: balanceActions.amount(10)
186+
};
187+
188+
const messages = [];
189+
190+
const fakeConsole = {
191+
log: (...args) => messages.push(args)
192+
};
193+
194+
const action$ = scheduler.createHotObservable('-a-b-c', actionsMap);
195+
196+
scheduler.expectObservable(
197+
loggingEpic(fakeConsole)(action$)
198+
).toBe('');
160199

161200
scheduler.flush();
162-
});
201+
202+
assertDeepEqual(messages, [
203+
['Dispatch [TRANSACTION_START]', actionsMap.a],
204+
['Dispatch [ACCOUNT_CHANGED]', actionsMap.b],
205+
['Dispatch [AMOUNT_CHANGED]', actionsMap.c]
206+
]);
207+
208+
})
163209
})
164210

165211
});

0 commit comments

Comments
 (0)