Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6bb9d76

Browse files
committed
feat(state): add accumulator fn injection token
Now we can provide a global accumulator fn using the token `ACCUMULATOR_FN_TOKEN` instead of repeating `state.setAccumulator(myAccumulator)` everywhere.
1 parent 9ff65f0 commit 6bb9d76

File tree

3 files changed

+166
-100
lines changed

3 files changed

+166
-100
lines changed

libs/state/selections/spec/accumulation-observable.spec.ts

Lines changed: 140 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import { jestMatcher } from '@test-helpers/rx-angular';
1+
import { TestBed } from '@angular/core/testing';
2+
import {
3+
createAccumulationObservable,
4+
select,
5+
} from '@rx-angular/state/selections';
26
import {
3-
initialPrimitiveState,
47
PrimitiveState,
8+
initialPrimitiveState,
9+
jestMatcher,
510
} from '@test-helpers/rx-angular';
611
import { of, throwError } from 'rxjs';
712
import { map } from 'rxjs/operators';
813
import { TestScheduler } from 'rxjs/testing';
9-
import { select } from '../src';
10-
import { createAccumulationObservable } from '../src/lib/accumulation-observable';
1114

1215
function setupAccumulationObservable<T extends object>(cfg: {
1316
initialState?: T;
@@ -24,165 +27,199 @@ function setupAccumulationObservable<T extends object>(cfg: {
2427
return acc;
2528
}
2629

30+
let testBed: TestBed;
2731
let testScheduler: TestScheduler;
2832

2933
beforeEach(() => {
34+
testBed = TestBed.configureTestingModule({});
3035
testScheduler = new TestScheduler(jestMatcher);
3136
});
3237

3338
describe('createAccumulationObservable', () => {
3439
it('should return object', () => {
35-
const acc = createAccumulationObservable();
36-
expect(acc).toBeDefined();
40+
testBed.runInInjectionContext(() => {
41+
const acc = createAccumulationObservable();
42+
expect(acc).toBeDefined();
43+
});
3744
});
3845

3946
describe('signal$', () => {
4047
it('should return NO empty base-state after init when subscribing late', () => {
4148
testScheduler.run(({ expectObservable }) => {
42-
const state = setupAccumulationObservable({});
43-
expectObservable(state.signal$).toBe('');
49+
testBed.runInInjectionContext(() => {
50+
const state = setupAccumulationObservable({});
51+
expectObservable(state.signal$).toBe('');
52+
});
4453
});
4554
});
4655

4756
it('should return No changes when subscribing late', () => {
4857
testScheduler.run(({ expectObservable }) => {
49-
const state = setupAccumulationObservable<PrimitiveState>({});
50-
state.subscribe();
58+
testBed.runInInjectionContext(() => {
59+
const state = setupAccumulationObservable<PrimitiveState>({});
60+
state.subscribe();
5161

52-
state.nextSlice({ num: 42 });
53-
expectObservable(state.signal$.pipe(map((s) => s.num))).toBe('');
62+
state.nextSlice({ num: 42 });
63+
expectObservable(state.signal$.pipe(map((s) => s.num))).toBe('');
64+
});
5465
});
5566
});
5667

5768
it('should return changes after subscription', () => {
58-
const state = setupAccumulationObservable<PrimitiveState>({});
59-
state.subscribe();
60-
state.nextSlice({ num: 42 });
61-
const slice$ = state.signal$.pipe(select('num'));
69+
testBed.runInInjectionContext(() => {
70+
const state = setupAccumulationObservable<PrimitiveState>({});
71+
state.subscribe();
72+
state.nextSlice({ num: 42 });
73+
const slice$ = state.signal$.pipe(select('num'));
6274

63-
let i = -1;
64-
const valuesInOrder = ['', { num: 777 }];
65-
slice$.subscribe((next) => expect(next).toBe(valuesInOrder[++i]));
66-
state.nextSlice({ num: 777 });
75+
let i = -1;
76+
const valuesInOrder = ['', { num: 777 }];
77+
slice$.subscribe((next) => expect(next).toBe(valuesInOrder[++i]));
78+
state.nextSlice({ num: 777 });
79+
});
6780
});
6881

6982
it('should log error if getting error', () => {
70-
const spy = jest.spyOn(console, 'error').mockImplementation();
71-
const state = setupAccumulationObservable<PrimitiveState>({});
72-
state.nextSliceObservable(throwError('test') as any);
73-
state.subscribe();
83+
testBed.runInInjectionContext(() => {
84+
const spy = jest.spyOn(console, 'error').mockImplementation();
85+
const state = setupAccumulationObservable<PrimitiveState>({});
86+
state.nextSliceObservable(throwError('test') as any);
87+
state.subscribe();
7488

75-
expect(spy).toBeCalled();
89+
expect(spy).toBeCalled();
90+
});
7691
});
7792
});
7893

7994
describe('state$', () => {
8095
it('should return nothing without subscriber', () => {
8196
testScheduler.run(({ expectObservable }) => {
82-
const acc = setupAccumulationObservable<PrimitiveState>({
83-
initialState: initialPrimitiveState,
84-
initialize: false,
97+
testBed.runInInjectionContext(() => {
98+
const acc = setupAccumulationObservable<PrimitiveState>({
99+
initialState: initialPrimitiveState,
100+
initialize: false,
101+
});
102+
expectObservable(acc.state$).toBe('');
85103
});
86-
expectObservable(acc.state$).toBe('');
87104
});
88105
});
89106

90107
it('should return nothing after init', () => {
91108
testScheduler.run(({ expectObservable }) => {
92-
const acc = setupAccumulationObservable<PrimitiveState>({
93-
initialize: true,
109+
testBed.runInInjectionContext(() => {
110+
const acc = setupAccumulationObservable<PrimitiveState>({
111+
initialize: true,
112+
});
113+
expectObservable(acc.state$).toBe('');
94114
});
95-
expectObservable(acc.state$).toBe('');
96115
});
97116
});
98117

99118
it('should return initial base-state', () => {
100119
testScheduler.run(({ expectObservable }) => {
101-
const acc = setupAccumulationObservable<PrimitiveState>({
102-
initialState: initialPrimitiveState,
120+
testBed.runInInjectionContext(() => {
121+
const acc = setupAccumulationObservable<PrimitiveState>({
122+
initialState: initialPrimitiveState,
123+
});
124+
expectObservable(acc.state$).toBe('s', { s: initialPrimitiveState });
103125
});
104-
expectObservable(acc.state$).toBe('s', { s: initialPrimitiveState });
105126
});
106127
});
107128
});
108129

109130
describe('state', () => {
110131
it('should return {} without subscriber', () => {
111-
const acc = setupAccumulationObservable<PrimitiveState>({
112-
initialize: false,
132+
testBed.runInInjectionContext(() => {
133+
const acc = setupAccumulationObservable<PrimitiveState>({
134+
initialize: false,
135+
});
136+
expect(acc.state).toStrictEqual({});
113137
});
114-
expect(acc.state).toStrictEqual({});
115138
});
116139

117140
it('should return {} with subscriber', () => {
118-
const acc = setupAccumulationObservable<PrimitiveState>({
119-
initialize: true,
141+
testBed.runInInjectionContext(() => {
142+
const acc = setupAccumulationObservable<PrimitiveState>({
143+
initialize: true,
144+
});
145+
expect(acc.state).toStrictEqual({});
120146
});
121-
expect(acc.state).toStrictEqual({});
122147
});
123148

124149
it('should return {} after init', () => {
125-
const acc = setupAccumulationObservable<PrimitiveState>({
126-
initialize: true,
150+
testBed.runInInjectionContext(() => {
151+
const acc = setupAccumulationObservable<PrimitiveState>({
152+
initialize: true,
153+
});
154+
expect(acc.state).toStrictEqual({});
127155
});
128-
expect(acc.state).toStrictEqual({});
129156
});
130157

131158
it('should return initial base-state', () => {
132-
const acc = setupAccumulationObservable<PrimitiveState>({
133-
initialState: initialPrimitiveState,
159+
testBed.runInInjectionContext(() => {
160+
const acc = setupAccumulationObservable<PrimitiveState>({
161+
initialState: initialPrimitiveState,
162+
});
163+
expect(acc.state).toEqual(initialPrimitiveState);
134164
});
135-
expect(acc.state).toEqual(initialPrimitiveState);
136165
});
137166
});
138167

139168
describe('nextSlice', () => {
140169
it('should add new base-state by partial', () => {
141170
testScheduler.run(({ expectObservable }) => {
142-
const acc = setupAccumulationObservable<PrimitiveState>({});
143-
acc.nextSlice({ num: 42 });
144-
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('s', {
145-
s: 42,
171+
testBed.runInInjectionContext(() => {
172+
const acc = setupAccumulationObservable<PrimitiveState>({});
173+
acc.nextSlice({ num: 42 });
174+
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('s', {
175+
s: 42,
176+
});
146177
});
147178
});
148179
});
149180

150181
it('should override previous base-state by partial', () => {
151-
const acc = setupAccumulationObservable<PrimitiveState>({
152-
initialState: initialPrimitiveState,
182+
testBed.runInInjectionContext(() => {
183+
const acc = setupAccumulationObservable<PrimitiveState>({
184+
initialState: initialPrimitiveState,
185+
});
186+
acc.state$
187+
.pipe(map((s) => s.num))
188+
.subscribe((res) => expect(res).toBe({ s: 42 }));
189+
acc.nextSlice({ num: 43 });
190+
acc.state$
191+
.pipe(map((s) => s.num))
192+
.subscribe((res) => expect(res).toBe({ s: 43 }));
153193
});
154-
acc.state$
155-
.pipe(map((s) => s.num))
156-
.subscribe((res) => expect(res).toBe({ s: 42 }));
157-
acc.nextSlice({ num: 43 });
158-
acc.state$
159-
.pipe(map((s) => s.num))
160-
.subscribe((res) => expect(res).toBe({ s: 43 }));
161194
});
162195
});
163196

164197
describe('connectState', () => {
165198
it('should add new slices', () => {
166199
testScheduler.run(({ expectObservable }) => {
167-
const acc = setupAccumulationObservable<PrimitiveState>({});
168-
acc.nextSliceObservable(of({ num: 42 }));
169-
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('s', {
170-
s: 42,
200+
testBed.runInInjectionContext(() => {
201+
const acc = setupAccumulationObservable<PrimitiveState>({});
202+
acc.nextSliceObservable(of({ num: 42 }));
203+
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('s', {
204+
s: 42,
205+
});
171206
});
172207
});
173208
});
174209

175210
it('should override previous base-state slices', () => {
176-
const acc = setupAccumulationObservable<PrimitiveState>({
177-
initialState: initialPrimitiveState,
211+
testBed.runInInjectionContext(() => {
212+
const acc = setupAccumulationObservable<PrimitiveState>({
213+
initialState: initialPrimitiveState,
214+
});
215+
acc.state$
216+
.pipe(map((s) => s.num))
217+
.subscribe((res) => expect(res).toBe({ s: 42 }));
218+
acc.nextSliceObservable(of({ num: 43 }));
219+
acc.state$
220+
.pipe(map((s) => s.num))
221+
.subscribe((res) => expect(res).toBe({ s: 42 }));
178222
});
179-
acc.state$
180-
.pipe(map((s) => s.num))
181-
.subscribe((res) => expect(res).toBe({ s: 42 }));
182-
acc.nextSliceObservable(of({ num: 43 }));
183-
acc.state$
184-
.pipe(map((s) => s.num))
185-
.subscribe((res) => expect(res).toBe({ s: 42 }));
186223
});
187224
});
188225

@@ -196,19 +233,21 @@ describe('createAccumulationObservable', () => {
196233
...sl,
197234
};
198235
};
199-
const acc = setupAccumulationObservable<PrimitiveState>({});
200-
testScheduler.run(({ expectObservable }) => {
201-
acc.nextSlice({ num: 42 });
202-
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('(a)', {
203-
a: 44,
236+
testBed.runInInjectionContext(() => {
237+
const acc = setupAccumulationObservable<PrimitiveState>({});
238+
testScheduler.run(({ expectObservable }) => {
239+
acc.nextSlice({ num: 42 });
240+
expectObservable(acc.state$.pipe(map((s) => s.num))).toBe('(a)', {
241+
a: 44,
242+
});
243+
244+
acc.nextAccumulator(customAcc);
245+
acc.nextSlice({ num: 43 });
246+
acc.nextSlice({ num: 44 });
204247
});
205248

206-
acc.nextAccumulator(customAcc);
207-
acc.nextSlice({ num: 43 });
208-
acc.nextSlice({ num: 44 });
249+
expect(numAccCalls).toBe(2);
209250
});
210-
211-
expect(numAccCalls).toBe(2);
212251
});
213252
});
214253

@@ -217,25 +256,29 @@ describe('createAccumulationObservable', () => {
217256
// the latest value emitted
218257
xit('should stop on unsubscribe from state', () => {
219258
testScheduler.run(({ expectObservable }) => {
220-
const acc = createAccumulationObservable<PrimitiveState>();
221-
const sub = acc.subscribe();
222-
acc.nextSlice(initialPrimitiveState);
223-
sub.unsubscribe();
224-
expectObservable(acc.state$).toBe('');
259+
testBed.runInInjectionContext(() => {
260+
const acc = createAccumulationObservable<PrimitiveState>();
261+
const sub = acc.subscribe();
262+
acc.nextSlice(initialPrimitiveState);
263+
sub.unsubscribe();
264+
expectObservable(acc.state$).toBe('');
265+
});
225266
});
226267
});
227268

228269
it('should stop from connect observable', () => {
229270
testScheduler.run(({ expectObservable, hot, expectSubscriptions }) => {
230-
const acc = createAccumulationObservable<PrimitiveState>();
231-
const sub = acc.subscribe();
232-
const tick$ = hot('aaaaaaaaaaaaaaa|', { a: 1 });
233-
const interval$ = tick$.pipe(map((num) => ({ num })));
234-
const subs = '(^!)';
235-
acc.nextSliceObservable(interval$);
236-
sub.unsubscribe();
237-
expectObservable(acc.state$).toBe('');
238-
expectSubscriptions(tick$.subscriptions).toBe(subs);
271+
testBed.runInInjectionContext(() => {
272+
const acc = createAccumulationObservable<PrimitiveState>();
273+
const sub = acc.subscribe();
274+
const tick$ = hot('aaaaaaaaaaaaaaa|', { a: 1 });
275+
const interval$ = tick$.pipe(map((num) => ({ num })));
276+
const subs = '(^!)';
277+
acc.nextSliceObservable(interval$);
278+
sub.unsubscribe();
279+
expectObservable(acc.state$).toBe('');
280+
expectSubscriptions(tick$.subscriptions).toBe(subs);
281+
});
239282
});
240283
});
241284
});

libs/state/selections/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
export { createAccumulationObservable } from './lib/accumulation-observable';
1+
export {
2+
createAccumulationObservable,
3+
ACCUMULATOR_FN_TOKEN,
4+
} from './lib/accumulation-observable';
25
export { CompareFn, KeyCompareMap, PickSlice } from './lib/interfaces/index';
36
export { AccumulationFn, Accumulator } from './lib/model';
47
export {

0 commit comments

Comments
 (0)