Skip to content

Commit

Permalink
feat(stock-market): added new ngrx functions
Browse files Browse the repository at this point in the history
  • Loading branch information
abedzantout committed Jul 3, 2019
1 parent c47dd9e commit 54272f8
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { SharedModule } from '../../../../shared/shared.module';

import { State } from '../../examples.state';
import { StockMarketService } from '../stock-market.service';
import { ActionStockMarketRetrieve } from '../stock-market.actions';
import { actionStockMarketRetrieve } from '../stock-market.actions';
import { StockMarketContainerComponent } from './stock-market-container.component';
import { StockMarketState } from '../stock-market.model';

Expand Down Expand Up @@ -85,7 +85,7 @@ describe('StockMarketContainerComponent', () => {
it('should trigger dispatch with correct input', () => {
expect(dispatchSpy).toHaveBeenCalledTimes(1);
expect(dispatchSpy).toHaveBeenCalledWith(
new ActionStockMarketRetrieve({ symbol: 'A' })
actionStockMarketRetrieve({ symbol: 'A' })
);
expect(true).toBeTruthy();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { take } from 'rxjs/operators';
import { ROUTE_ANIMATIONS_ELEMENTS } from '../../../../core/core.module';

import { selectStockMarket } from '../stock-market.selectors';
import { ActionStockMarketRetrieve } from '../stock-market.actions';
import { actionStockMarketRetrieve } from '../stock-market.actions';
import { StockMarketState } from '../stock-market.model';
import { State } from '../../examples.state';

Expand All @@ -30,6 +30,6 @@ export class StockMarketContainerComponent implements OnInit {
}

onSymbolChange(symbol: string) {
this.store.dispatch(new ActionStockMarketRetrieve({ symbol }));
this.store.dispatch(actionStockMarketRetrieve({ symbol }));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Action } from '@ngrx/store';
import { createAction, props } from '@ngrx/store';
import { HttpErrorResponse } from '@angular/common/http';

import { Stock } from './stock-market.model';
Expand All @@ -9,25 +9,17 @@ export enum StockMarketActionTypes {
RETRIEVE_ERROR = '[Stock] Retrieve Error'
}

export class ActionStockMarketRetrieve implements Action {
readonly type = StockMarketActionTypes.RETRIEVE;
export const actionStockMarketRetrieve = createAction(
StockMarketActionTypes.RETRIEVE,
props<{ symbol: string }>()
);

constructor(readonly payload: { symbol: string }) {}
}

export class ActionStockMarketRetrieveSuccess implements Action {
readonly type = StockMarketActionTypes.RETRIEVE_SUCCESS;

constructor(readonly payload: { stock: Stock }) {}
}

export class ActionStockMarketRetrieveError implements Action {
readonly type = StockMarketActionTypes.RETRIEVE_ERROR;

constructor(readonly payload: { error: HttpErrorResponse }) {}
}
export const actionStockMarketRetrieveSuccess = createAction(
StockMarketActionTypes.RETRIEVE_SUCCESS,
props<{ stock: Stock }>()
);

export type StockMarketActions =
| ActionStockMarketRetrieve
| ActionStockMarketRetrieveSuccess
| ActionStockMarketRetrieveError;
export const actionStockMarketRetrieveError = createAction(
StockMarketActionTypes.RETRIEVE_ERROR,
props<{ error: HttpErrorResponse }>()
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { TestScheduler } from 'rxjs/testing';
import { LocalStorageService } from '../../../core/core.module';

import {
ActionStockMarketRetrieve,
ActionStockMarketRetrieveError,
ActionStockMarketRetrieveSuccess
actionStockMarketRetrieve,
actionStockMarketRetrieveError,
actionStockMarketRetrieveSuccess
} from './stock-market.actions';
import { StockMarketEffects, STOCK_MARKET_KEY } from './stock-market.effects';
import { Stock } from './stock-market.model';
Expand All @@ -32,13 +32,13 @@ describe('StockMarketEffects', () => {
it('should emit ActionStockMarketRetrieveSuccess on success', done => {
scheduler.run(helpers => {
const { cold, expectObservable } = helpers;
const retrieveAction1 = new ActionStockMarketRetrieve({
const retrieveAction1 = actionStockMarketRetrieve({
symbol
});
const retrieveAction2 = new ActionStockMarketRetrieve({
const retrieveAction2 = actionStockMarketRetrieve({
symbol
});
const retrieveAction3 = new ActionStockMarketRetrieve({
const retrieveAction3 = actionStockMarketRetrieve({
symbol
});
const stock: Stock = {
Expand All @@ -51,7 +51,7 @@ describe('StockMarketEffects', () => {
changeNegative: false,
changePercent: '2.00'
};
const successAction = new ActionStockMarketRetrieveSuccess({
const successAction = actionStockMarketRetrieveSuccess({
stock
});
const values = {
Expand All @@ -72,11 +72,10 @@ describe('StockMarketEffects', () => {
stockMarket
);

expectObservable(
effects.retrieveStock({
debounce: 2
})
).toBe(expected, values);
expectObservable(effects.retrieveStock({ debounce: 2 })).toBe(
expected,
values
);

setTimeout(() => {
expect(localStorage.setItem).toHaveBeenCalledTimes(3);
Expand All @@ -91,11 +90,11 @@ describe('StockMarketEffects', () => {
it('should emit ActionStockMarketRetrieveError on error', () => {
scheduler.run(helpers => {
const { cold, expectObservable } = helpers;
const retrieveAction = new ActionStockMarketRetrieve({
const retrieveAction = actionStockMarketRetrieve({
symbol
});
const error = 'ERROR';
const errorAction = new ActionStockMarketRetrieveError({
const errorAction = actionStockMarketRetrieveError({
error
} as any);
const values = {
Expand All @@ -114,11 +113,10 @@ describe('StockMarketEffects', () => {
stockMarket
);

expectObservable(
effects.retrieveStock({
debounce: 0
})
).toBe(expected, values);
expectObservable(effects.retrieveStock({ debounce: 0 })).toBe(
expected,
values
);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { asyncScheduler, of } from 'rxjs';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, debounceTime, map, switchMap, tap } from 'rxjs/operators';

import { LocalStorageService } from '../../../core/core.module';

import {
ActionStockMarketRetrieve,
ActionStockMarketRetrieveError,
ActionStockMarketRetrieveSuccess,
StockMarketActionTypes
actionStockMarketRetrieve,
actionStockMarketRetrieveError,
actionStockMarketRetrieveSuccess
} from './stock-market.actions';
import { StockMarketService } from './stock-market.service';

Expand All @@ -19,26 +17,26 @@ export const STOCK_MARKET_KEY = 'EXAMPLES.STOCKS';
@Injectable()
export class StockMarketEffects {
constructor(
private actions$: Actions<Action>,
private actions$: Actions,
private localStorageService: LocalStorageService,
private service: StockMarketService
) {}

@Effect()
retrieveStock = ({ debounce = 500 } = {}) =>
retrieveStock = createEffect(() => ({ debounce = 500 } = {}) =>
this.actions$.pipe(
ofType<ActionStockMarketRetrieve>(StockMarketActionTypes.RETRIEVE),
ofType(actionStockMarketRetrieve),
tap(action =>
this.localStorageService.setItem(STOCK_MARKET_KEY, {
symbol: action.payload.symbol
symbol: action.symbol
})
),
debounceTime(debounce),
switchMap((action: ActionStockMarketRetrieve) =>
this.service.retrieveStock(action.payload.symbol).pipe(
map(stock => new ActionStockMarketRetrieveSuccess({ stock })),
catchError(error => of(new ActionStockMarketRetrieveError({ error })))
switchMap(action =>
this.service.retrieveStock(action.symbol).pipe(
map(stock => actionStockMarketRetrieveSuccess({ stock })),
catchError(error => of(actionStockMarketRetrieveError({ error })))
)
)
);
)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { Stock, StockMarketState } from './stock-market.model';
import { HttpErrorResponse } from '@angular/common/http';
import { stockMarketReducer, initialState } from './stock-market.reducer';
import {
StockMarketActions,
ActionStockMarketRetrieve,
ActionStockMarketRetrieveError,
ActionStockMarketRetrieveSuccess
actionStockMarketRetrieve,
actionStockMarketRetrieveError,
actionStockMarketRetrieveSuccess
} from './stock-market.actions';

const originalState: StockMarketState = {
Expand All @@ -27,7 +26,7 @@ describe('StockMarketReducer', () => {
describe('undefined action', () => {
describe('with undefined original state', () => {
it('should return the initial state', () => {
const action = {} as StockMarketActions;
const action = {} as any;
const state = stockMarketReducer(undefined, action);

expect(state).toBe(initialState);
Expand All @@ -36,7 +35,7 @@ describe('StockMarketReducer', () => {

describe('with a valid original state', () => {
it('should return the original state', () => {
const action = {} as StockMarketActions;
const action = {} as any;
const state = stockMarketReducer(originalState, action);

expect(state).toBe(originalState);
Expand All @@ -46,20 +45,20 @@ describe('StockMarketReducer', () => {

describe('RETRIEVE action', () => {
it('should reflect that it has started loading the provided symbol', () => {
const action = new ActionStockMarketRetrieve({ symbol: 'AEONS' });
const action = actionStockMarketRetrieve({ symbol: 'AEONS' });
const state = stockMarketReducer(originalState, action);

expect(state.loading).toBeTruthy();
expect(state.stock).toBeNull();
expect(state.error).toBeNull();
expect(state.symbol).toBe(action.payload.symbol);
expect(state.symbol).toBe(action.symbol);
});
});

describe('RETRIEVE_ERROR action', () => {
it('should reflect the Error that occured', () => {
const error = new HttpErrorResponse({});
const action = new ActionStockMarketRetrieveError({ error: error });
const action = actionStockMarketRetrieveError({ error: error });
const state = stockMarketReducer(originalState, action);

expect(state.symbol).toBe(state.symbol);
Expand All @@ -81,7 +80,7 @@ describe('StockMarketReducer', () => {
changeNegative: false,
changePercent: '+5%'
};
const action = new ActionStockMarketRetrieveSuccess({ stock: stock });
const action = actionStockMarketRetrieveSuccess({ stock: stock });
const state = stockMarketReducer(originalState, action);

expect(state.loading).toBeFalsy();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
import { StockMarketState } from './stock-market.model';
import {
StockMarketActions,
StockMarketActionTypes
actionStockMarketRetrieve,
actionStockMarketRetrieveError,
actionStockMarketRetrieveSuccess
} from './stock-market.actions';
import { Action, createReducer, on } from '@ngrx/store';

export const initialState: StockMarketState = {
symbol: 'GOOGL',
loading: false
};

export function stockMarketReducer(
state: StockMarketState = initialState,
action: StockMarketActions
): StockMarketState {
switch (action.type) {
case StockMarketActionTypes.RETRIEVE:
return {
...state,
loading: true,
stock: null,
error: null,
symbol: action.payload.symbol
};

case StockMarketActionTypes.RETRIEVE_SUCCESS:
return {
...state,
loading: false,
stock: action.payload.stock,
error: null
};
const reducer = createReducer(
initialState,
on(actionStockMarketRetrieve, (state, { symbol }) => ({
...state,
loading: true,
stock: null,
error: null,
symbol
})),
on(actionStockMarketRetrieveSuccess, (state, { stock }) => ({
...state,
loading: false,
stock,
error: null
})),
on(actionStockMarketRetrieveError, (state, { error }) => ({
...state,
loading: false,
stock: null,
error
}))
);

case StockMarketActionTypes.RETRIEVE_ERROR:
return {
...state,
loading: false,
stock: null,
error: action.payload.error
};

default:
return state;
}
export function stockMarketReducer(
state: StockMarketState | undefined,
action: Action
) {
return reducer(state, action);
}

0 comments on commit 54272f8

Please sign in to comment.