From 628b865e84277902e2bebbeb1171986e70cc32a3 Mon Sep 17 00:00:00 2001 From: Denis Loginov Date: Wed, 18 Oct 2017 09:22:56 -0400 Subject: [PATCH] feat(Effects): Add getEffectsMetadata() helper for verifying metadata Closes #491 --- docs/effects/testing.md | 42 ++++++++++++++++++- modules/effects/spec/effects_metadata.spec.ts | 33 +++++++++++++++ modules/effects/src/effects_metadata.ts | 18 ++++++++ modules/effects/src/index.ts | 6 ++- 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/docs/effects/testing.md b/docs/effects/testing.md index b3112255c0..4e42e0c732 100644 --- a/docs/effects/testing.md +++ b/docs/effects/testing.md @@ -47,6 +47,46 @@ describe('My Effects', () => { effects.someSource$.subscribe(result => { expect(result).toEqual(AnotherAction); }); - }); + }); +}); +``` + +### getEffectsMetadata +Returns decorator configuration for all effects in a class instance. +Use this function to ensure that effects have been properly decorated. + +Usage: +```ts +import { TestBed } from '@angular/core/testing'; +import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects'; +import { MyEffects } from './my-effects'; + +describe('My Effects', () => { + let effects: MyEffects; + let metadata: EffectsMetadata; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + MyEffects, + // other providers + ], + }); + + effects = TestBed.get(MyEffects); + metadata = getEffectsMetadata(effects); + }); + + it('should register someSource$ that dispatches an action', () => { + expect(metadata.someSource$).toEqual({ dispatch: true }); + }); + + it('should register someOtherSource$ that does not dispatch an action', () => { + expect(metadata.someOtherSource$).toEqual({ dispatch: false }); + }); + + it('should not register undecoratedSource$', () => { + expect(metadata.undecoratedSource$).toBeUndefined(); + }); }); ``` \ No newline at end of file diff --git a/modules/effects/spec/effects_metadata.spec.ts b/modules/effects/spec/effects_metadata.spec.ts index 223927a19f..42e80deede 100644 --- a/modules/effects/spec/effects_metadata.spec.ts +++ b/modules/effects/spec/effects_metadata.spec.ts @@ -1,5 +1,6 @@ import { Effect, + getEffectsMetadata, getSourceMetadata, getSourceForInstance, } from '../src/effects_metadata'; @@ -46,4 +47,36 @@ describe('Effect Metadata', () => { expect(proto).toBe(Fixture.prototype); }); }); + + describe('getEffectsMetadata', () => { + it('should get map of metadata for all decorated effects in a class instance', () => { + class Fixture { + @Effect() a: any; + @Effect({ dispatch: true }) + b: any; + @Effect({ dispatch: false }) + c: any; + } + + const mock = new Fixture(); + + expect(getEffectsMetadata(mock)).toEqual({ + a: { dispatch: true }, + b: { dispatch: true }, + c: { dispatch: false }, + }); + }); + + it('should return an empty map if the class has not been decorated', () => { + class Fixture { + a: any; + b: any; + c: any; + } + + const mock = new Fixture(); + + expect(getEffectsMetadata(mock)).toEqual({}); + }); + }); }); diff --git a/modules/effects/src/effects_metadata.ts b/modules/effects/src/effects_metadata.ts index 02d6c5779b..3efe9e033d 100644 --- a/modules/effects/src/effects_metadata.ts +++ b/modules/effects/src/effects_metadata.ts @@ -40,3 +40,21 @@ export const getSourceMetadata = compose( getEffectMetadataEntries, getSourceForInstance ); + +export type EffectsMetadata = { + [key in keyof T]?: + | undefined + | { + dispatch: boolean; + } +}; + +export function getEffectsMetadata(instance: T): EffectsMetadata { + const metadata: EffectsMetadata = {}; + + getSourceMetadata(instance).forEach(({ propertyName, dispatch }) => { + metadata[propertyName] = { dispatch }; + }); + + return metadata; +} diff --git a/modules/effects/src/index.ts b/modules/effects/src/index.ts index 691f22608a..f54bf2c415 100644 --- a/modules/effects/src/index.ts +++ b/modules/effects/src/index.ts @@ -1,4 +1,8 @@ -export { Effect } from './effects_metadata'; +export { + Effect, + EffectsMetadata, + getEffectsMetadata, +} from './effects_metadata'; export { mergeEffects } from './effects_resolver'; export { Actions } from './actions'; export { EffectsModule } from './effects_module';