Skip to content

Commit 9b45f1c

Browse files
fix: make withUndoRedo sync with watchState instead of effect [backport v19]
- fix #190: make withUndoRedo sync with watchState instead of effect - make tests synchronous and remove fakeAsync and tick
1 parent f60bedc commit 9b45f1c

File tree

2 files changed

+21
-33
lines changed

2 files changed

+21
-33
lines changed

libs/ngrx-toolkit/src/lib/with-undo-redo.spec.ts

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { computed, inject } from '@angular/core';
2-
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
2+
import { TestBed } from '@angular/core/testing';
33
import {
44
patchState,
55
signalStore,
@@ -73,7 +73,7 @@ describe('withUndoRedo', () => {
7373
});
7474

7575
describe('undo and redo', () => {
76-
it('restores previous state for regular store key', fakeAsync(() => {
76+
it('restores previous state for regular store key', () => {
7777
TestBed.runInInjectionContext(() => {
7878
const Store = signalStore(
7979
withState(testState),
@@ -85,24 +85,22 @@ describe('withUndoRedo', () => {
8585
);
8686

8787
const store = new Store();
88-
tick(1);
8988

9089
store.updateTest(newValue);
91-
tick(1);
90+
9291
expect(store.test()).toEqual(newValue);
9392
expect(store.canUndo()).toBe(true);
9493
expect(store.canRedo()).toBe(false);
9594

9695
store.undo();
97-
tick(1);
9896

9997
expect(store.test()).toEqual('');
10098
expect(store.canUndo()).toBe(false);
10199
expect(store.canRedo()).toBe(true);
102100
});
103-
}));
101+
});
104102

105-
it('restores previous state for regular store key and respects skip', fakeAsync(() => {
103+
it('restores previous state for regular store key and respects skip', () => {
106104
TestBed.runInInjectionContext(() => {
107105
const Store = signalStore(
108106
withState(testState),
@@ -114,30 +112,26 @@ describe('withUndoRedo', () => {
114112
);
115113

116114
const store = new Store();
117-
tick(1);
118115

119116
store.updateTest(newValue);
120-
tick(1);
117+
121118
expect(store.test()).toEqual(newValue);
122119

123120
store.updateTest(newerValue);
124-
tick(1);
125121

126122
store.undo();
127-
tick(1);
128123

129124
expect(store.test()).toEqual(newValue);
130125
expect(store.canUndo()).toBe(false);
131126

132127
store.undo();
133-
tick(1);
134128

135129
// should not change
136130
expect(store.test()).toEqual(newValue);
137131
});
138-
}));
132+
});
139133

140-
it('undoes and redoes previous state for entity', fakeAsync(() => {
134+
it('undoes and redoes previous state for entity', () => {
141135
const Store = signalStore(
142136
withEntities({ entity: type<{ id: string }>() }),
143137
withMethods((store) => ({
@@ -149,19 +143,19 @@ describe('withUndoRedo', () => {
149143
TestBed.configureTestingModule({ providers: [Store] });
150144
TestBed.runInInjectionContext(() => {
151145
const store = inject(Store);
152-
tick(1);
146+
153147
expect(store.entities()).toEqual([]);
154148
expect(store.canUndo()).toBe(false);
155149
expect(store.canRedo()).toBe(false);
156150

157151
store.addEntity(newValue);
158-
tick(1);
152+
159153
expect(store.entities()).toEqual([{ id: newValue }]);
160154
expect(store.canUndo()).toBe(true);
161155
expect(store.canRedo()).toBe(false);
162156

163157
store.addEntity(newerValue);
164-
tick(1);
158+
165159
expect(store.entities()).toEqual([
166160
{ id: newValue },
167161
{ id: newerValue },
@@ -182,21 +176,20 @@ describe('withUndoRedo', () => {
182176
expect(store.canRedo()).toBe(true);
183177

184178
store.redo();
185-
tick(1);
186179

187180
expect(store.entities()).toEqual([{ id: newValue }]);
188181
expect(store.canUndo()).toBe(true);
189182
expect(store.canRedo()).toBe(true);
190183

191184
// should return canRedo=false after a change
192185
store.addEntity('newest');
193-
tick(1);
186+
194187
expect(store.canUndo()).toBe(true);
195188
expect(store.canRedo()).toBe(false);
196189
});
197-
}));
190+
});
198191

199-
it('restores previous state for named entity', fakeAsync(() => {
192+
it('restores previous state for named entity', () => {
200193
TestBed.runInInjectionContext(() => {
201194
const Store = signalStore(
202195
withEntities({
@@ -215,22 +208,20 @@ describe('withUndoRedo', () => {
215208
);
216209

217210
const store = new Store();
218-
tick(1);
219211

220212
store.addEntity(newValue);
221-
tick(1);
213+
222214
expect(store.flightEntities()).toEqual([{ id: newValue }]);
223215
expect(store.canUndo()).toBe(true);
224216
expect(store.canRedo()).toBe(false);
225217

226218
store.undo();
227-
tick(1);
228219

229220
expect(store.flightEntities()).toEqual([]);
230221
expect(store.canUndo()).toBe(false);
231222
expect(store.canRedo()).toBe(true);
232223
});
233-
}));
224+
});
234225

235226
it('clears undo redo stack', () => {
236227
const Store = signalStore(
@@ -253,7 +244,7 @@ describe('withUndoRedo', () => {
253244
expect(store.canRedo()).toBe(false);
254245
});
255246

256-
it('cannot undo after clearing and setting a new value', fakeAsync(() => {
247+
it('cannot undo after clearing and setting a new value', () => {
257248
const Store = signalStore(
258249
{ providedIn: 'root' },
259250
withState(testState),
@@ -266,22 +257,18 @@ describe('withUndoRedo', () => {
266257
const store = TestBed.inject(Store);
267258

268259
store.update('Alan');
269-
tick(1);
270260

271261
store.update('Gordon');
272-
tick(1);
273262

274263
store.clearStack();
275-
tick(1);
276264

277265
// After clearing the undo/redo stack, there is no previous item anymore.
278266
// The following update becomes the first value.
279267
// Since there is no other value before, it cannot be undone.
280268
store.update('Hugh');
281-
tick(1);
282269

283270
expect(store.canUndo()).toBe(false);
284271
expect(store.canRedo()).toBe(false);
285-
}));
272+
});
286273
});
287274
});

libs/ngrx-toolkit/src/lib/with-undo-redo.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { Signal, effect, isSignal, signal, untracked } from '@angular/core';
1+
import { Signal, isSignal, signal, untracked } from '@angular/core';
22
import {
33
EmptyFeatureResult,
44
SignalStoreFeature,
55
SignalStoreFeatureResult,
66
patchState,
77
signalStoreFeature,
8+
watchState,
89
withComputed,
910
withHooks,
1011
withMethods,
@@ -143,7 +144,7 @@ export function withUndoRedo<Input extends EmptyFeatureResult>(
143144
})),
144145
withHooks({
145146
onInit(store) {
146-
effect(() => {
147+
watchState(store, () => {
147148
const cand = keys.reduce((acc, key) => {
148149
const s = (store as Record<string | keyof Input['state'], unknown>)[
149150
key

0 commit comments

Comments
 (0)