NgRx Selectors

Selectors are pure functions used for obtaining slices of store state.

Selector by route

This will select based on route data, example: /invoice/123

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--- foo.facade.ts
public getCurrentInvoice (): Observable<IStoreItem<IInvoice>> {
return this._store.select(InvoiceSelectors.byRoute).pipe(
// tap(a => console.log(a)),
filter(a => a.isLoading === false),
dispatchAndSelect(
invoice => this._store.dispatch(new GetInvoiceAction(invoice)),
this._store.select(InvoiceSelectors.currentInvoice)
)
);
}

--- foo.selectors.ts
export const byRoute = createSelector(
RouterSelectors.currentParams,
(params: Params): string => {
return params.id;
}
);

export const currentInvoice = createSelector(
selectFeature,
(state: FeatureState) => state.counter
);

IStoreItem is just a way to wrap the response and universally (thought-out your application) check if the store slice ready.

1
2
3
4
export interface IStoreItem<T> {
isLoading: boolean;
item?: T;
}

Using selectors with props

To select a piece of state based on data that isn’t available in the store you can pass props to the selector function.

1
2
3
4
5
6
7
8
9
10
11
12
--- foo.facade.ts
public getCurrentInvoice (): Observable<IStoreItem<IInvoice>> {
return this._store.pipe(select(fromRoot.getCount, { multiply: 2 }))
}

--- foo.selectors.ts
--- here `counter` is the response from `getCounterValue` and `props` came from the call to `getCount` above. NgRx is wierd :D

export const getCount = createSelector(
getCounterValue,
(counter, props) => counter * props.multiply
);

Jest

Jest is a javaScript testing framework.

1
2
3
4
5
6
7
toHaveBeenCalledWith

toBeInstanceOf

toBe

toMatchSnapshot

TestBed with mockReturnValue

This can be called inside the tests body to mock out the function getFeatures

1
TestBed.get(SomeFacade).getFeatures = jest.fn().mockReturnValue(of());

Data driven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
--- with toBeObservable
describe('[childComponentEnabled$]', () => {
[
{ abName: true, expected: true },
{ abName: false, expected: false }
].forEach(({ abName, expected }) =>
it(`should ${expected ? '' : 'not'} use 'child-component-to-maybe-show' if abName feature is ${abName}`, marbles((m) => {
// Arrange
const fixture = TestBed.createComponent(ParentComponent);
const testComponent = fixture.componentInstance;
const abFeature = <IAbFeature> {
name: 'abName',
value: abName.toString(),
winningVariantName: 'OnVariant'
};
TestBed.get(AbFrameworkFacade).getByName = () => of(abFeature);

// Act
fixture.detectChanges();

// Assert
m.expect(testComponent.childComponentEnabled$).toBeObservable('(a|)', {
a: expected
});
}))
);
});

--- passing the array elements by object `testcase`
describe(`getSomeMethod`, () => {
[
{
someObject: {},
someBool: true,
someString: 'hoe',
someEnum: SomeEnum.hoe,
expected: 'foo'
},
{
someObject: {},
someBool: true,
someString: 'bazz',
someEnum: SomeEnum.foo,
expected: 'foo bar'
}
].forEach(testcase => {
it(`does some sweet thing,
testcase ${JSON.stringify(testcase)}`, () => {
// do all the things and set `actual`
const actual = 'wat';
expect(actual).toBe(testcase.expected);
});
});
});

References

Raspberry Pi Cluster

Docker Swarm

Python Example

Sweet python script example to warm the Pi’s CPU!

References