-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(Effects): Simplified AP, added better error reporting and ef…
…fects stream control BREAKING CHANGES: Effects API for registering effects has been updated to allow for multiple classes to be provided. BEFORE: ```ts @NgModule({ imports: [ EffectsModule.run(SourceA), EffectsModule.run(SourceB) ] }) export class AppModule { } ``` AFTER: ```ts @NgModule({ imports: [ EffectsModule.forRoot([ SourceA, SourceB, SourceC, ]) ] }) export class AppModule { } @NgModule({ imports: [ EffectsModule.forFeature([ FeatureSourceA, FeatureSourceB, FeatureSourceC, ]) ] }) export class SomeFeatureModule { } ```
- Loading branch information
1 parent
e21d688
commit 015107f
Showing
37 changed files
with
673 additions
and
572 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import 'rxjs/add/operator/concat'; | ||
import 'rxjs/add/operator/catch'; | ||
import { cold } from 'jasmine-marbles'; | ||
import { Observable } from 'rxjs/Observable'; | ||
import { of } from 'rxjs/observable/of'; | ||
import { _throw } from 'rxjs/observable/throw'; | ||
import { never } from 'rxjs/observable/never'; | ||
import { empty } from 'rxjs/observable/empty'; | ||
import { TestBed } from '@angular/core/testing'; | ||
import { ErrorReporter } from '../src/error_reporter'; | ||
import { CONSOLE } from '../src/tokens'; | ||
import { Effect, EffectSources } from '../'; | ||
|
||
describe('EffectSources', () => { | ||
let mockErrorReporter: ErrorReporter; | ||
let effectSources: EffectSources; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
providers: [ | ||
EffectSources, | ||
ErrorReporter, | ||
{ | ||
provide: CONSOLE, | ||
useValue: console, | ||
}, | ||
], | ||
}); | ||
|
||
mockErrorReporter = TestBed.get(ErrorReporter); | ||
effectSources = TestBed.get(EffectSources); | ||
|
||
spyOn(mockErrorReporter, 'report'); | ||
}); | ||
|
||
it('should have an "addEffects" method to push new source instances', () => { | ||
const effectSource = {}; | ||
spyOn(effectSources, 'next'); | ||
|
||
effectSources.addEffects(effectSource); | ||
|
||
expect(effectSources.next).toHaveBeenCalledWith(effectSource); | ||
}); | ||
|
||
describe('toActions() Operator', () => { | ||
const a = { type: 'From Source A' }; | ||
const b = { type: 'From Source B' }; | ||
const c = { type: 'From Source C that completes' }; | ||
const d = { not: 'a valid action' }; | ||
const error = new Error('An Error'); | ||
|
||
class SourceA { | ||
@Effect() a$ = alwaysOf(a); | ||
} | ||
|
||
class SourceB { | ||
@Effect() b$ = alwaysOf(b); | ||
} | ||
|
||
class SourceC { | ||
@Effect() c$ = of(c); | ||
} | ||
|
||
class SourceD { | ||
@Effect() d$ = alwaysOf(d); | ||
} | ||
|
||
class SourceE { | ||
@Effect() e$ = _throw(error); | ||
} | ||
|
||
it('should resolve effects from instances', () => { | ||
const sources$ = cold('--a--', { a: new SourceA() }); | ||
const expected = cold('--a--', { a }); | ||
|
||
const output = toActions(sources$); | ||
|
||
expect(output).toBeObservable(expected); | ||
}); | ||
|
||
it('should ignore duplicate sources', () => { | ||
const sources$ = cold('--a--b--c--', { | ||
a: new SourceA(), | ||
b: new SourceA(), | ||
c: new SourceA(), | ||
}); | ||
const expected = cold('--a--------', { a }); | ||
|
||
const output = toActions(sources$); | ||
|
||
expect(output).toBeObservable(expected); | ||
}); | ||
|
||
it('should report an error if an effect dispatches an invalid action', () => { | ||
const sources$ = of(new SourceD()); | ||
|
||
toActions(sources$).subscribe(); | ||
|
||
expect(mockErrorReporter.report).toHaveBeenCalled(); | ||
}); | ||
|
||
function toActions(source: any): Observable<any> { | ||
source['errorReporter'] = mockErrorReporter; | ||
return effectSources.toActions.call(source); | ||
} | ||
}); | ||
|
||
function alwaysOf<T>(value: T) { | ||
return of(value).concat(never<T>()); | ||
} | ||
}); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { TestBed } from '@angular/core/testing'; | ||
import { EffectSources } from '../src/effect_sources'; | ||
import { FEATURE_EFFECTS } from '../src/tokens'; | ||
import { EffectsFeatureModule } from '../src/effects_feature_module'; | ||
|
||
describe('Effects Feature Module', () => { | ||
const sourceA = 'sourceA'; | ||
const sourceB = 'sourceB'; | ||
const sourceC = 'sourceC'; | ||
const effectSourceGroups = [[sourceA], [sourceB], [sourceC]]; | ||
let mockEffectSources: { addEffects: jasmine.Spy }; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
providers: [ | ||
{ | ||
provide: EffectSources, | ||
useValue: { | ||
addEffects: jasmine.createSpy('addEffects'), | ||
}, | ||
}, | ||
{ | ||
provide: FEATURE_EFFECTS, | ||
useValue: effectSourceGroups, | ||
}, | ||
EffectsFeatureModule, | ||
], | ||
}); | ||
|
||
mockEffectSources = TestBed.get(mockEffectSources); | ||
}); | ||
|
||
it('should add all effects when instantiated', () => { | ||
TestBed.get(EffectsFeatureModule); | ||
|
||
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceA); | ||
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceB); | ||
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceC); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Effect, getSourceMetadata, getSourceForInstance } from '../src/effects_metadata'; | ||
|
||
describe('Effect Metadata', () => { | ||
describe('getSourceMetadata', () => { | ||
it('should get the effects metadata for a class instance', () => { | ||
class Fixture { | ||
@Effect() a: any; | ||
@Effect() b: any; | ||
@Effect({ dispatch: false }) c: any; | ||
} | ||
|
||
const mock = new Fixture(); | ||
|
||
expect(getSourceMetadata(mock)).toEqual([ | ||
{ propertyName: 'a', dispatch: true }, | ||
{ propertyName: 'b', dispatch: true }, | ||
{ propertyName: 'c', dispatch: false } | ||
]); | ||
}); | ||
|
||
it('should return an empty array if the class has not been decorated', () => { | ||
class Fixture { | ||
a: any; | ||
b: any; | ||
c: any; | ||
} | ||
|
||
const mock = new Fixture(); | ||
|
||
expect(getSourceMetadata(mock)).toEqual([]); | ||
}); | ||
}); | ||
|
||
describe('getSourceProto', () => { | ||
it('should get the prototype for an instance of a source', () => { | ||
class Fixture { } | ||
const instance = new Fixture(); | ||
|
||
const proto = getSourceForInstance(instance); | ||
|
||
expect(proto).toBe(Fixture.prototype); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import 'rxjs/add/observable/of'; | ||
import { Observable } from 'rxjs/Observable'; | ||
import { Effect, mergeEffects } from '../'; | ||
|
||
|
||
describe('mergeEffects', () => { | ||
|
||
}); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.