Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose @Effect() metadata for testing #493

Merged
merged 11 commits into from
Oct 18, 2017
42 changes: 41 additions & 1 deletion docs/effects/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<MyEffects>;

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();
});
});
```
33 changes: 33 additions & 0 deletions modules/effects/spec/effects_metadata.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Effect,
getEffectsMetadata,
getSourceMetadata,
getSourceForInstance,
} from '../src/effects_metadata';
Expand Down Expand Up @@ -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({});
});
});
});
18 changes: 18 additions & 0 deletions modules/effects/src/effects_metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@ export const getSourceMetadata = compose(
getEffectMetadataEntries,
getSourceForInstance
);

export type EffectsMetadata<T> = {
[key in keyof T]?:
| undefined
| {
dispatch: boolean;
}
};

export function getEffectsMetadata<T>(instance: T): EffectsMetadata<T> {
const metadata: EffectsMetadata<T> = {};

getSourceMetadata(instance).forEach(({ propertyName, dispatch }) => {
metadata[propertyName] = { dispatch };
});

return metadata;
}
6 changes: 5 additions & 1 deletion modules/effects/src/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down