1
- import { patchState , signalStore , type , withComputed , withMethods , withState } from '@ngrx/signals ' ;
1
+ import { computed , inject } from '@angular/core ' ;
2
2
import { fakeAsync , TestBed , tick } from '@angular/core/testing' ;
3
- import { withUndoRedo } from './with-undo-redo' ;
3
+ import {
4
+ patchState ,
5
+ signalStore ,
6
+ type ,
7
+ withComputed ,
8
+ withMethods ,
9
+ withState ,
10
+ } from '@ngrx/signals' ;
4
11
import { addEntity , withEntities } from '@ngrx/signals/entities' ;
5
- import { computed , inject } from '@angular/core' ;
6
12
import { withCallState } from './with-call-state' ;
13
+ import { withUndoRedo } from './with-undo-redo' ;
7
14
8
15
const testState = { test : '' } ;
9
16
const testKeys = [ 'test' as const ] ;
@@ -13,7 +20,10 @@ const newerValue = 'newer value';
13
20
describe ( 'withUndoRedo' , ( ) => {
14
21
it ( 'adds methods for undo, redo, canUndo, canRedo' , ( ) => {
15
22
TestBed . runInInjectionContext ( ( ) => {
16
- const Store = signalStore ( withState ( testState ) , withUndoRedo ( { keys : testKeys } ) ) ;
23
+ const Store = signalStore (
24
+ withState ( testState ) ,
25
+ withUndoRedo ( { keys : testKeys } )
26
+ ) ;
17
27
const store = new Store ( ) ;
18
28
19
29
expect ( Object . keys ( store ) ) . toEqual ( [
@@ -22,39 +32,55 @@ describe('withUndoRedo', () => {
22
32
'canRedo' ,
23
33
'undo' ,
24
34
'redo' ,
25
- 'clearStack'
35
+ 'clearStack' ,
26
36
] ) ;
27
37
} ) ;
28
38
} ) ;
29
39
30
40
it ( 'should check keys and collection types' , ( ) => {
31
- signalStore ( withState ( testState ) ,
41
+ signalStore (
42
+ withState ( testState ) ,
32
43
// @ts -expect-error - should not allow invalid keys
33
- withUndoRedo ( { keys : [ 'tes' ] } ) ) ;
34
- signalStore ( withState ( testState ) ,
44
+ withUndoRedo ( { keys : [ 'tes' ] } )
45
+ ) ;
46
+ signalStore (
47
+ withState ( testState ) ,
35
48
withEntities ( { entity : type ( ) , collection : 'flight' } ) ,
36
49
// @ts -expect-error - should not allow invalid keys when entities are present
37
- withUndoRedo ( { keys : [ 'flightIdsTest' ] } ) ) ;
38
- signalStore ( withState ( testState ) ,
50
+ withUndoRedo ( { keys : [ 'flightIdsTest' ] } )
51
+ ) ;
52
+ signalStore (
53
+ withState ( testState ) ,
39
54
// @ts -expect-error - should not allow collections without named entities
40
- withUndoRedo ( { collections : [ 'tee' ] } ) ) ;
41
- signalStore ( withState ( testState ) , withComputed ( store => ( { testComputed : computed ( ( ) => store . test ( ) ) } ) ) ,
55
+ withUndoRedo ( { collections : [ 'tee' ] } )
56
+ ) ;
57
+ signalStore (
58
+ withState ( testState ) ,
59
+ withComputed ( ( store ) => ( { testComputed : computed ( ( ) => store . test ( ) ) } ) ) ,
42
60
// @ts -expect-error - should not allow collections without named entities with other computed
43
- withUndoRedo ( { collections : [ 'tested' ] } ) ) ;
44
- signalStore ( withEntities ( { entity : type ( ) } ) ,
61
+ withUndoRedo ( { collections : [ 'tested' ] } )
62
+ ) ;
63
+ signalStore (
64
+ withEntities ( { entity : type ( ) } ) ,
45
65
// @ts -expect-error - should not allow collections without named entities
46
- withUndoRedo ( { collections : [ 'test' ] } ) ) ;
47
- signalStore ( withEntities ( { entity : type ( ) , collection : 'flight' } ) ,
66
+ withUndoRedo ( { collections : [ 'test' ] } )
67
+ ) ;
68
+ signalStore (
69
+ withEntities ( { entity : type ( ) , collection : 'flight' } ) ,
48
70
// @ts -expect-error - should not allow invalid collections
49
- withUndoRedo ( { collections : [ 'test' ] } ) ) ;
71
+ withUndoRedo ( { collections : [ 'test' ] } )
72
+ ) ;
50
73
} ) ;
51
74
52
75
describe ( 'undo and redo' , ( ) => {
53
76
it ( 'restores previous state for regular store key' , fakeAsync ( ( ) => {
54
77
TestBed . runInInjectionContext ( ( ) => {
55
78
const Store = signalStore (
56
79
withState ( testState ) ,
57
- withMethods ( store => ( { updateTest : ( newTest : string ) => patchState ( store , { test : newTest } ) } ) ) ,
80
+ withMethods ( ( store ) => ( {
81
+ updateTest : ( newTest : string ) =>
82
+ patchState ( store , { test : newTest } ) ,
83
+ } ) ) ,
58
84
withUndoRedo ( { keys : testKeys } )
59
85
) ;
60
86
@@ -80,7 +106,10 @@ describe('withUndoRedo', () => {
80
106
TestBed . runInInjectionContext ( ( ) => {
81
107
const Store = signalStore (
82
108
withState ( testState ) ,
83
- withMethods ( store => ( { updateTest : ( newTest : string ) => patchState ( store , { test : newTest } ) } ) ) ,
109
+ withMethods ( ( store ) => ( {
110
+ updateTest : ( newTest : string ) =>
111
+ patchState ( store , { test : newTest } ) ,
112
+ } ) ) ,
84
113
withUndoRedo ( { keys : testKeys , skip : 1 } )
85
114
) ;
86
115
@@ -111,8 +140,9 @@ describe('withUndoRedo', () => {
111
140
it ( 'undoes and redoes previous state for entity' , fakeAsync ( ( ) => {
112
141
const Store = signalStore (
113
142
withEntities ( { entity : type < { id : string } > ( ) } ) ,
114
- withMethods ( store => ( {
115
- addEntity : ( newTest : string ) => patchState ( store , addEntity ( { id : newTest } ) )
143
+ withMethods ( ( store ) => ( {
144
+ addEntity : ( newTest : string ) =>
145
+ patchState ( store , addEntity ( { id : newTest } ) ) ,
116
146
} ) ) ,
117
147
withUndoRedo ( )
118
148
) ;
@@ -132,7 +162,10 @@ describe('withUndoRedo', () => {
132
162
133
163
store . addEntity ( newerValue ) ;
134
164
tick ( 1 ) ;
135
- expect ( store . entities ( ) ) . toEqual ( [ { id : newValue } , { id : newerValue } ] ) ;
165
+ expect ( store . entities ( ) ) . toEqual ( [
166
+ { id : newValue } ,
167
+ { id : newerValue } ,
168
+ ] ) ;
136
169
expect ( store . canUndo ( ) ) . toBe ( true ) ;
137
170
expect ( store . canRedo ( ) ) . toBe ( false ) ;
138
171
@@ -166,9 +199,16 @@ describe('withUndoRedo', () => {
166
199
it ( 'restores previous state for named entity' , fakeAsync ( ( ) => {
167
200
TestBed . runInInjectionContext ( ( ) => {
168
201
const Store = signalStore (
169
- withEntities ( { entity : type < { id : string } > ( ) , collection : 'flight' } ) ,
170
- withMethods ( store => ( {
171
- addEntity : ( newTest : string ) => patchState ( store , addEntity ( { id : newTest } , { collection : 'flight' } ) )
202
+ withEntities ( {
203
+ entity : type < { id : string } > ( ) ,
204
+ collection : 'flight' ,
205
+ } ) ,
206
+ withMethods ( ( store ) => ( {
207
+ addEntity : ( newTest : string ) =>
208
+ patchState (
209
+ store ,
210
+ addEntity ( { id : newTest } , { collection : 'flight' } )
211
+ ) ,
172
212
} ) ) ,
173
213
withCallState ( { collection : 'flight' } ) ,
174
214
withUndoRedo ( { collections : [ 'flight' ] } )
@@ -196,7 +236,9 @@ describe('withUndoRedo', () => {
196
236
const Store = signalStore (
197
237
{ providedIn : 'root' } ,
198
238
withState ( testState ) ,
199
- withMethods ( store => ( { update : ( value : string ) => patchState ( store , { test : value } ) } ) ) ,
239
+ withMethods ( ( store ) => ( {
240
+ update : ( value : string ) => patchState ( store , { test : value } ) ,
241
+ } ) ) ,
200
242
withUndoRedo ( { keys : testKeys } )
201
243
) ;
202
244
@@ -209,6 +251,38 @@ describe('withUndoRedo', () => {
209
251
210
252
expect ( store . canUndo ( ) ) . toBe ( false ) ;
211
253
expect ( store . canRedo ( ) ) . toBe ( false ) ;
212
- } )
254
+ } ) ;
255
+
256
+ it ( 'can undo after clearing and setting the same value again' , fakeAsync ( ( ) => {
257
+ const recordState = { customer : { firstname : 'Santa' } } ;
258
+
259
+ const Store = signalStore (
260
+ { providedIn : 'root' } ,
261
+ withState ( recordState ) ,
262
+ withMethods ( ( store ) => ( {
263
+ update : ( value : typeof recordState ) => patchState ( store , value ) ,
264
+ } ) ) ,
265
+ withUndoRedo ( { keys : [ 'customer' ] } )
266
+ ) ;
267
+
268
+ const store = TestBed . inject ( Store ) ;
269
+
270
+ store . update ( { customer : { firstname : 'Alan' } } ) ;
271
+ tick ( 1 ) ;
272
+
273
+ store . update ( { customer : { firstname : 'Gordon' } } ) ;
274
+ tick ( 1 ) ;
275
+
276
+ store . clearStack ( ) ;
277
+ tick ( 1 ) ;
278
+
279
+ // After clearing the undo/redo stack, there is no previous item any more
280
+ // The following update is the very first value.
281
+ store . update ( { customer : { firstname : 'Hugh' } } ) ;
282
+ tick ( 1 ) ;
283
+
284
+ expect ( store . canUndo ( ) ) . toBe ( false ) ;
285
+ expect ( store . canRedo ( ) ) . toBe ( false ) ;
286
+ } ) ) ;
213
287
} ) ;
214
288
} ) ;
0 commit comments