Skip to content

Commit

Permalink
Merge branch 'master' into pr/core-barrel-imports
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonhodges authored May 17, 2019
2 parents 82eeba8 + 4a5153c commit 47b1853
Show file tree
Hide file tree
Showing 54 changed files with 1,027 additions and 172 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
<a name="8.0.0-beta.2"></a>

# [8.0.0-beta.2](https://github.com/ngrx/platform/compare/8.0.0-beta.1...8.0.0-beta.2) (2019-05-15)

### Bug Fixes

- **data:** update the package name for replacement to ngrx-data ([#1805](https://github.com/ngrx/platform/issues/1805)) ([00c00e0](https://github.com/ngrx/platform/commit/00c00e0)), closes [#1802](https://github.com/ngrx/platform/issues/1802)
- **example:** resolve circular dependency ([#1833](https://github.com/ngrx/platform/issues/1833)) ([1fbd59c](https://github.com/ngrx/platform/commit/1fbd59c))

### Features

- **effects:** add mapToAction operator ([#1822](https://github.com/ngrx/platform/issues/1822)) ([1ff986f](https://github.com/ngrx/platform/commit/1ff986f)), closes [#1224](https://github.com/ngrx/platform/issues/1224)
- **store:** add option to mock selectors in MockStoreConfig ([#1836](https://github.com/ngrx/platform/issues/1836)) ([070228c](https://github.com/ngrx/platform/commit/070228c)), closes [#1827](https://github.com/ngrx/platform/issues/1827)
- **store:** expand createReducer type signature to support up to ten action creators ([#1803](https://github.com/ngrx/platform/issues/1803)) ([63e4926](https://github.com/ngrx/platform/commit/63e4926))
- **store:** warn when same action is registered ([#1801](https://github.com/ngrx/platform/issues/1801)) ([ecda5f7](https://github.com/ngrx/platform/commit/ecda5f7)), closes [#1758](https://github.com/ngrx/platform/issues/1758)

### Reverts

- warn when same action is registered ([#1801](https://github.com/ngrx/platform/issues/1801)) ([#1841](https://github.com/ngrx/platform/issues/1841)) ([b07ae4e](https://github.com/ngrx/platform/commit/b07ae4e))

<a name="8.0.0-beta.1"></a>

# [8.0.0-beta.1](https://github.com/ngrx/platform/compare/8.0.0-beta.0...8.0.0-beta.1) (2019-04-24)
Expand Down
34 changes: 34 additions & 0 deletions modules/effects/spec/actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,38 @@ describe('Actions', function() {
dispatcher.next(multiply({ by: 2 }));
dispatcher.complete();
});

it('should support more than 5 actions', () => {
const log = createAction('logarithm');
const expected = [
divide.type,
ADD,
square.type,
SUBTRACT,
multiply.type,
log.type,
];

actions$
.pipe(
// Mixing all of them, more than 5. It still works, but we loose the type info
ofType(divide, ADD, square, SUBTRACT, multiply, log),
map(update => update.type),
toArray()
)
.subscribe({
next(actual) {
expect(actual).toEqual(expected);
},
});

// Actions under test, in specific order
dispatcher.next(divide({ by: 1 }));
dispatcher.next({ type: ADD });
dispatcher.next(square());
dispatcher.next({ type: SUBTRACT });
dispatcher.next(multiply({ by: 2 }));
dispatcher.next(log());
dispatcher.complete();
});
});
286 changes: 286 additions & 0 deletions modules/effects/spec/map_to_action.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
import { cold, hot } from 'jasmine-marbles';
import { mergeMap, take, switchMap } from 'rxjs/operators';
import { createAction, Action } from '@ngrx/store';
import { mapToAction } from '@ngrx/effects';
import { throwError, Subject } from 'rxjs';

describe('mapToAction operator', () => {
/**
* Helper function that converts a string (or array of letters) into the
* object, each property of which is a letter that is assigned an Action
* with type as that letter.
*
* e.g. genActions('abc') would result in
* {
* 'a': {type: 'a'},
* 'b': {type: 'b'},
* 'c': {type: 'c'},
* }
*/
function genActions(marbles: string): { [marble: string]: Action } {
return marbles.split('').reduce(
(acc, marble) => {
return {
...acc,
[marble]: createAction(marble)(),
};
},
{} as { [marble: string]: Action }
);
}

it('should call project functon', () => {
const sources$ = hot('-a-b', genActions('ab'));

const actual$ = new Subject();
const project = jasmine
.createSpy('project')
.and.callFake((...args: [Action, number]) => {
actual$.next(args);
return cold('(v|)', genActions('v'));
});
const error = () => createAction('e')();

sources$.pipe(mapToAction(project, error)).subscribe();

expect(actual$).toBeObservable(
cold(' -a-b', {
a: [createAction('a')(), 0],
b: [createAction('b')(), 1],
})
);
});

it('should emit output action', () => {
const sources$ = hot(' -a', genActions('a'));
const project = () => cold('(v|)', genActions('v'));
const error = () => createAction('e')();
const expected$ = cold('-v', genActions('v'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should take any type of Observable as an Input', () => {
const sources$ = hot(' -a', { a: 'a string' });
const project = () => cold('(v|)', genActions('v'));
const error = () => createAction('e')();
const expected$ = cold('-v', genActions('v'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should emit output action with config passed', () => {
const sources$ = hot(' -a', genActions('a'));
// Completes
const project = () => cold('(v|)', genActions('v'));
const error = () => createAction('e')();
// offset by source delay and doesn't complete
const expected$ = cold('-v--', genActions('v'));

const output$ = sources$.pipe(mapToAction({ project, error }));

expect(output$).toBeObservable(expected$);
});

it('should call the error callback when error in the project occurs', () => {
const sources$ = hot(' -a', genActions('a'));
const project = () => throwError('error');
const error = () => createAction('e')();
const expected$ = cold('-e', genActions('e'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should continue listen to the sources actions after error occurs', () => {
const sources$ = hot('-a--b', genActions('ab'));
const project = (action: Action) =>
action.type === 'a' ? throwError('error') : cold('(v|)', genActions('v'));
const error = () => createAction('e')();
// error handler action is dispatched and next action with type b is also
// handled
const expected$ = cold('-e--v', genActions('ev'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should emit multiple output actions when project produces many actions', () => {
const sources$ = hot(' -a', genActions('a'));
const project = () => cold('v-w-x-(y|)', genActions('vwxy'));
const error = () => createAction('e')();
// offset by source delay and doesn't complete
const expected$ = cold('-v-w-x-y--', genActions('vwxy'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should emit multiple output actions when project produces many actions with config passed', () => {
const sources$ = hot(' -a', genActions('a'));
const project = () => cold('v-w-x-(y|)', genActions('vwxy'));
const error = () => createAction('e')();
// offset by source delay
const expected$ = cold('-v-w-x-y', genActions('vwxy'));

const output$ = sources$.pipe(mapToAction({ project, error }));

expect(output$).toBeObservable(expected$);
});

it('should emit multiple output actions when source produces many actions', () => {
const sources$ = hot(' -a--b', genActions('ab'));
const project = () => cold('(v|)', genActions('v'));
const error = () => createAction('e')();

const expected$ = cold('-v--v-', genActions('v'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should emit multiple output actions when source produces many actions with config passed', () => {
const sources$ = hot(' -a--b', genActions('ab'));
const project = () => cold('(v|)', genActions('v'));
const error = () => createAction('e')();

const expected$ = cold('-v--v-', genActions('v'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should flatten projects with concatMap by default', () => {
const sources$ = hot(' -a--b', genActions('ab'));
const project = () => cold('v------(w|)', genActions('vw'));
const error = () => createAction('e')();

// Even thought source produced actions one right after another, operator
// wait for the project to complete before handling second source action.
const expected$ = cold('-v------(wv)---w', genActions('vw'));

const output$ = sources$.pipe(mapToAction(project, error));

expect(output$).toBeObservable(expected$);
});

it('should flatten projects with concatMap by default with config passed', () => {
const sources$ = hot(' -a--b', genActions('ab'));
const project = () => cold('v------(w|)', genActions('vw'));
const error = () => createAction('e')();

// Even thought source produced actions one right after another, operator
// wait for the project to complete before handling second source action.
const expected$ = cold('-v------(wv)---w', genActions('vw'));

const output$ = sources$.pipe(mapToAction({ project, error }));

expect(output$).toBeObservable(expected$);
});

it('should use provided flattening operator', () => {
const sources$ = hot(' -a--b', genActions('ab'));
const project = () => cold('v------(w|)', genActions('vw'));
const error = () => createAction('e')();

// Merge map starts project streams in parallel
const expected$ = cold('-v--v---w--w', genActions('vw'));

const output$ = sources$.pipe(
mapToAction({ project, error, operator: mergeMap })
);

expect(output$).toBeObservable(expected$);
});

it('should use provided complete callback', () => {
const sources$ = hot(' -a', genActions('a'));
const project = () => cold('v-|', genActions('v'));
const error = () => createAction('e')();
const complete = () => createAction('c')();

// Completed is the last action
const expected$ = cold('-v-c', genActions('vc'));

const output$ = sources$.pipe(mapToAction({ project, error, complete }));

expect(output$).toBeObservable(expected$);
});

it('should pass number of observables that project emitted and input action to complete callback', () => {
const sources$ = hot('-a', genActions('a'));
const project = () => cold('v-w-|', genActions('v'));
const error = () => createAction('e')();

const actual$ = new Subject();

const complete = jasmine
.createSpy('complete')
.and.callFake((...args: [number, Action]) => {
actual$.next(args);
return createAction('c')();
});

sources$.pipe(mapToAction({ project, error, complete })).subscribe();

expect(actual$).toBeObservable(
cold('-----a', {
a: [2, createAction('a')()],
})
);
});

it('should use provided unsubscribe callback', () => {
const sources$ = hot(' -a-b', genActions('ab'));
const project = () => cold('v-----w|', genActions('vw'));
const error = () => createAction('e')();
const unsubscribe = () => createAction('u')();

// switchMap causes unsubscription
const expected$ = cold('-v-(uv)--w', genActions('vuw'));

const output$ = sources$.pipe(
mapToAction({ project, error, unsubscribe, operator: switchMap })
);

expect(output$).toBeObservable(expected$);
});

it(
'should pass number of observables that project emitted before' +
' unsubscribing and prior input action to unsubsubscribe callback',
() => {
const sources$ = hot('-a-b', genActions('ab'));
const project = () => cold('vw----v|', genActions('vw'));
const error = () => createAction('e')();

const actual$ = new Subject();

const unsubscribe = jasmine
.createSpy('unsubscribe')
.and.callFake((...args: [number, Action]) => {
actual$.next(args);
return createAction('u')();
});

sources$
.pipe(mapToAction({ project, error, unsubscribe, operator: switchMap }))
.subscribe();

expect(actual$).toBeObservable(
cold('---a', {
a: [2, createAction('a')()],
})
);
}
);
});
1 change: 1 addition & 0 deletions modules/effects/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { EffectsModule } from './effects_module';
export { EffectSources } from './effect_sources';
export { EffectNotification } from './effect_notification';
export { ROOT_EFFECTS_INIT } from './effects_root_module';
export { mapToAction } from './map_to_action';
export {
OnIdentifyEffects,
OnRunEffects,
Expand Down
Loading

0 comments on commit 47b1853

Please sign in to comment.