stunk 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/core/asyncChunk.d.ts +4 -4
  3. package/dist/core/asyncChunk.js +2 -3
  4. package/dist/core/computed.js +36 -24
  5. package/dist/core/selector.js +3 -17
  6. package/dist/core/types.d.ts +3 -3
  7. package/dist/use-react/hooks/useAsyncChunk.d.ts +3 -3
  8. package/dist/use-react/hooks/useAsyncChunk.js +1 -1
  9. package/package.json +26 -14
  10. package/jest.config.js +0 -4
  11. package/src/core/asyncChunk.ts +0 -83
  12. package/src/core/computed.ts +0 -65
  13. package/src/core/core.ts +0 -128
  14. package/src/core/selector.ts +0 -27
  15. package/src/core/types.ts +0 -17
  16. package/src/index.ts +0 -10
  17. package/src/middleware/history.ts +0 -113
  18. package/src/middleware/index.ts +0 -7
  19. package/src/middleware/logger.ts +0 -6
  20. package/src/middleware/persistence.ts +0 -45
  21. package/src/middleware/validator.ts +0 -8
  22. package/src/use-react/hooks/useAsyncChunk.ts +0 -38
  23. package/src/use-react/hooks/useChunk.ts +0 -40
  24. package/src/use-react/hooks/useChunkProperty.ts +0 -21
  25. package/src/use-react/hooks/useChunkValue.ts +0 -15
  26. package/src/use-react/hooks/useChunkValues.ts +0 -35
  27. package/src/use-react/hooks/useComputed.ts +0 -34
  28. package/src/use-react/hooks/useDerive.ts +0 -15
  29. package/src/use-react/index.ts +0 -9
  30. package/src/utils.ts +0 -103
  31. package/tests/async-chunk.test.ts +0 -215
  32. package/tests/batch-chunk.test.ts +0 -108
  33. package/tests/chunk.test.ts +0 -189
  34. package/tests/computed.test.ts +0 -93
  35. package/tests/history.test.ts +0 -99
  36. package/tests/middleware.test.ts +0 -37
  37. package/tests/persist.test.ts +0 -57
  38. package/tests/select-chunk.test.ts +0 -133
  39. package/tests/update.test.ts +0 -70
  40. package/tsconfig.json +0 -23
@@ -1,215 +0,0 @@
1
- import { asyncChunk } from '../src/core/asyncChunk';
2
- import { combineAsyncChunks } from '../src/utils';
3
-
4
- // Mock types for testing
5
- interface User {
6
- id: number;
7
- name: string;
8
- }
9
-
10
- interface Post {
11
- id: number;
12
- title: string;
13
- }
14
-
15
- describe('asyncChunk', () => {
16
- // Helper to create a delayed response
17
- const createDelayedResponse = <T>(data: T, delay = 50): Promise<T> => {
18
- return new Promise((resolve) => setTimeout(() => resolve(data), delay));
19
- };
20
-
21
- it('should handle successful async operations', async () => {
22
- const mockUser: User = { id: 1, name: 'Test User' };
23
- const userChunk = asyncChunk<User>(async () => {
24
- return createDelayedResponse(mockUser);
25
- });
26
-
27
- // Initial state
28
- expect(userChunk.get()).toEqual({
29
- loading: true,
30
- error: null,
31
- data: null
32
- });
33
-
34
- // Wait for async operation to complete
35
- await new Promise(resolve => setTimeout(resolve, 100));
36
-
37
- // Check final state
38
- expect(userChunk.get()).toEqual({
39
- loading: false,
40
- error: null,
41
- data: mockUser
42
- });
43
- });
44
-
45
- it('should handle errors', async () => {
46
- const errorMessage = 'Failed to fetch';
47
- const userChunk = asyncChunk<User>(async () => {
48
- throw new Error(errorMessage);
49
- });
50
-
51
- // Wait for async operation to complete
52
- await new Promise(resolve => setTimeout(resolve, 100));
53
-
54
- const state = userChunk.get();
55
- expect(state.loading).toBe(false);
56
- expect(state.error?.message).toBe(errorMessage);
57
- expect(state.data).toBe(null);
58
- });
59
-
60
- it('should handle retries', async () => {
61
- let attempts = 0;
62
- const mockUser: User = { id: 1, name: 'Test User' };
63
-
64
- const userChunk = asyncChunk<User>(
65
- async () => {
66
- attempts++;
67
- if (attempts < 3) {
68
- throw new Error('Temporary error');
69
- }
70
- return mockUser;
71
- },
72
- { retryCount: 2, retryDelay: 50 }
73
- );
74
-
75
- // Wait for all retries to complete
76
- await new Promise(resolve => setTimeout(resolve, 200));
77
-
78
- expect(attempts).toBe(3);
79
- expect(userChunk.get().data).toEqual(mockUser);
80
- });
81
-
82
- it('should support optimistic updates via mutate', () => {
83
- const mockUser: User = { id: 1, name: 'Test User' };
84
- const userChunk = asyncChunk<User>(async () => mockUser);
85
-
86
- userChunk.mutate(current => ({
87
- ...current!,
88
- name: 'Updated Name'
89
- }));
90
-
91
- const state = userChunk.get();
92
- expect(state.data?.name).toBe('Updated Name');
93
- });
94
-
95
- it('should reload data when requested', async () => {
96
- let counter = 0;
97
- const userChunk = asyncChunk<User>(async () => {
98
- counter++;
99
- return { id: counter, name: `User ${counter}` };
100
- });
101
-
102
- // Wait for initial load
103
- await new Promise(resolve => setTimeout(resolve, 100));
104
- expect(userChunk.get().data?.id).toBe(1);
105
-
106
- // Trigger reload
107
- await userChunk.reload();
108
- expect(userChunk.get().data?.id).toBe(2);
109
- });
110
- });
111
-
112
- describe('combineAsyncChunks', () => {
113
- it('should combine multiple async chunks', async () => {
114
- const mockUser: User = { id: 1, name: 'Test User' };
115
- const mockPosts: Post[] = [
116
- { id: 1, title: 'Post 1' },
117
- { id: 2, title: 'Post 2' }
118
- ];
119
-
120
- const userChunk = asyncChunk<User>(async () => {
121
- return createDelayedResponse(mockUser, 50);
122
- });
123
-
124
- const postsChunk = asyncChunk<Post[]>(async () => {
125
- return createDelayedResponse(mockPosts, 100);
126
- });
127
-
128
- const combined = combineAsyncChunks({
129
- user: userChunk,
130
- posts: postsChunk
131
- });
132
-
133
- // Initial state
134
- expect(combined.get()).toEqual({
135
- loading: true,
136
- error: null,
137
- data: {
138
- user: null,
139
- posts: null
140
- }
141
- });
142
-
143
- // Wait for all async operations to complete
144
- await new Promise(resolve => setTimeout(resolve, 150));
145
-
146
- // Check final state
147
- expect(combined.get()).toEqual({
148
- loading: false,
149
- error: null,
150
- data: {
151
- user: mockUser,
152
- posts: mockPosts
153
- }
154
- });
155
- });
156
-
157
- it('should handle errors in combined chunks', async () => {
158
- const mockUser: User = { id: 1, name: 'Test User' };
159
- const errorMessage = 'Failed to fetch posts';
160
-
161
- const userChunk = asyncChunk<User>(async () => {
162
- return createDelayedResponse(mockUser, 50);
163
- });
164
-
165
- const postsChunk = asyncChunk<Post[]>(async () => {
166
- throw new Error(errorMessage);
167
- });
168
-
169
- const combined = combineAsyncChunks({
170
- user: userChunk,
171
- posts: postsChunk
172
- });
173
-
174
- // Wait for all operations to complete
175
- await new Promise(resolve => setTimeout(resolve, 150));
176
-
177
- const state = combined.get();
178
- expect(state.loading).toBe(false);
179
- expect(state.error?.message).toBe(errorMessage);
180
- expect(state.data.user).toEqual(mockUser);
181
- expect(state.data.posts).toBe(null);
182
- });
183
-
184
- it('should update loading state correctly', async () => {
185
- const loadingStates: boolean[] = [];
186
- const userChunk = asyncChunk<User>(async () => {
187
- return createDelayedResponse({ id: 1, name: 'Test User' }, 50);
188
- });
189
-
190
- const postsChunk = asyncChunk<Post[]>(async () => {
191
- return createDelayedResponse([], 100);
192
- });
193
-
194
- const combined = combineAsyncChunks({
195
- user: userChunk,
196
- posts: postsChunk
197
- });
198
-
199
- combined.subscribe(state => {
200
- loadingStates.push(state.loading);
201
- });
202
-
203
- // Wait for all operations
204
- await new Promise(resolve => setTimeout(resolve, 150));
205
-
206
- // Should start with loading true and end with false
207
- expect(loadingStates[0]).toBe(true);
208
- expect(loadingStates[loadingStates.length - 1]).toBe(false);
209
- });
210
- });
211
-
212
- // Helper function
213
- function createDelayedResponse<T>(data: T, delay = 50): Promise<T> {
214
- return new Promise((resolve) => setTimeout(() => resolve(data), delay));
215
- }
@@ -1,108 +0,0 @@
1
- import { chunk, batch } from '../src/core/core';
2
-
3
-
4
- describe('Chunk batch updates', () => {
5
- it('should batch multiple updates into a single notification', () => {
6
- const countChunk = chunk(0);
7
- const callback = jest.fn();
8
-
9
- countChunk.subscribe(callback);
10
- callback.mockClear(); // Clear initial subscription call
11
-
12
- batch(() => {
13
- countChunk.set(1);
14
- countChunk.set(2);
15
- countChunk.set(3); // Should only notify once
16
- });
17
-
18
- expect(callback).toHaveBeenCalledTimes(1);
19
- expect(callback).toHaveBeenLastCalledWith(3);
20
- });
21
-
22
- it('should handle nested batch calls', () => {
23
- const countChunk = chunk(0);
24
- const callback = jest.fn();
25
-
26
- countChunk.subscribe(callback);
27
- callback.mockClear();
28
-
29
- batch(() => {
30
- countChunk.set(1); // Should not notify yet
31
- batch(() => {
32
- countChunk.set(2);
33
- countChunk.set(3);
34
- });
35
- countChunk.set(4);
36
- });
37
-
38
- expect(callback).toHaveBeenCalledTimes(1);
39
- expect(callback).toHaveBeenLastCalledWith(4);
40
- });
41
-
42
- it('should handle errors in batch without breaking state', () => {
43
- const countChunk = chunk(0);
44
- const callback = jest.fn();
45
-
46
- countChunk.subscribe(callback);
47
- callback.mockClear();
48
-
49
- expect(() => {
50
- batch(() => {
51
- countChunk.set(1);
52
- throw new Error('Test error');
53
- // countChunk.set(2);
54
- });
55
- }).toThrow('Test error');
56
-
57
- expect(callback).toHaveBeenCalledTimes(1);
58
- expect(callback).toHaveBeenLastCalledWith(1);
59
- expect(countChunk.get()).toBe(1);
60
- });
61
-
62
- it('should work with multiple chunks in the same batch', () => {
63
- const chunk1 = chunk(0);
64
- const chunk2 = chunk(0);
65
- const callback1 = jest.fn();
66
- const callback2 = jest.fn();
67
-
68
- chunk1.subscribe(callback1);
69
- chunk2.subscribe(callback2);
70
- callback1.mockClear();
71
- callback2.mockClear();
72
-
73
- batch(() => {
74
- chunk1.set(1);
75
- chunk2.set(1);
76
- chunk1.set(2);
77
- chunk2.set(2);
78
- });
79
-
80
- expect(callback1).toHaveBeenCalledTimes(1);
81
- expect(callback2).toHaveBeenCalledTimes(1);
82
- expect(callback1).toHaveBeenLastCalledWith(2);
83
- expect(callback2).toHaveBeenLastCalledWith(2);
84
- });
85
-
86
- it('should handle derived chunks in batch updates', () => {
87
- const sourceChunk = chunk(0);
88
- const derivedChunk = sourceChunk.derive(x => x * 2);
89
- const sourceCallback = jest.fn();
90
- const derivedCallback = jest.fn();
91
-
92
- sourceChunk.subscribe(sourceCallback);
93
- derivedChunk.subscribe(derivedCallback);
94
- sourceCallback.mockClear();
95
- derivedCallback.mockClear();
96
-
97
- batch(() => {
98
- sourceChunk.set(1);
99
- sourceChunk.set(2);
100
- sourceChunk.set(3);
101
- });
102
-
103
- expect(sourceCallback).toHaveBeenCalledTimes(1);
104
- expect(derivedCallback).toHaveBeenCalledTimes(1);
105
- expect(sourceCallback).toHaveBeenLastCalledWith(3);
106
- expect(derivedCallback).toHaveBeenLastCalledWith(6);
107
- });
108
- });
@@ -1,189 +0,0 @@
1
- import { chunk } from "../src/core/core";
2
-
3
- test("Chunk should get and set values correctly", () => {
4
- const chunky = chunk<number>(0);
5
- expect(chunky.get()).toBe(0);
6
- chunky.set(10);
7
- expect(chunky.get()).toBe(10);
8
- chunky.set((prev) => prev + 1);
9
- expect(chunky.get()).toBe(11);
10
- });
11
-
12
- test("Chunk should notify subscribers on value change", () => {
13
- const chunky = chunk<number>(0);
14
- const callback = jest.fn();
15
- const unsubscribe = chunky.subscribe(callback); // Store unsubscribe function
16
-
17
- chunky.set(5);
18
- expect(callback).toHaveBeenCalledWith(5);
19
-
20
- chunky.set(10);
21
- expect(callback).toHaveBeenCalledWith(10);
22
-
23
- unsubscribe(); // Ensure cleanup after test
24
- });
25
-
26
- test("Chunk should notify multiple subscribers correctly", () => {
27
- const chunky = chunk<number>(0);
28
- const callback1 = jest.fn();
29
- const callback2 = jest.fn();
30
-
31
- const unsubscribe1 = chunky.subscribe(callback1);
32
- const unsubscribe2 = chunky.subscribe(callback2);
33
-
34
-
35
- chunky.set(10);
36
-
37
- expect(callback1).toHaveBeenCalledWith(10);
38
- expect(callback2).toHaveBeenCalledWith(10);
39
-
40
- unsubscribe1();
41
- unsubscribe2();
42
- });
43
-
44
-
45
- test("Chunk should allow unsubscribing from updates", () => {
46
- const chunky = chunk<number>(0);
47
- const callback = jest.fn();
48
- const unsubscribe = chunky.subscribe(callback);
49
-
50
- // Initial subscription call
51
- expect(callback).toHaveBeenCalledWith(0);
52
- expect(callback).toHaveBeenCalledTimes(1);
53
-
54
- chunky.set(5);
55
- expect(callback).toHaveBeenCalledWith(5);
56
- expect(callback).toHaveBeenCalledTimes(2);
57
-
58
- unsubscribe();
59
- chunky.set(10);
60
- expect(callback).toHaveBeenCalledTimes(2); // Still called only twice
61
- });
62
-
63
- describe("Chunk Derivation", () => {
64
- it("should create a derived chunk and update it when the original chunk changes", () => {
65
- const count = chunk(5);
66
- const doubleCount = count.derive((value) => value * 2);
67
-
68
- const countSpy = jest.fn();
69
- const doubleCountSpy = jest.fn();
70
-
71
- // Subscribe to both chunks
72
- count.subscribe(countSpy);
73
- doubleCount.subscribe(doubleCountSpy);
74
-
75
- // Initial values
76
- expect(count.get()).toBe(5);
77
- expect(doubleCount.get()).toBe(10);
78
- expect(countSpy).toHaveBeenCalledWith(5);
79
- expect(doubleCountSpy).toHaveBeenCalledWith(10);
80
-
81
- // Update count and verify updates
82
- count.set(10);
83
- expect(count.get()).toBe(10);
84
- expect(doubleCount.get()).toBe(20);
85
- expect(countSpy).toHaveBeenCalledWith(10);
86
- expect(doubleCountSpy).toHaveBeenCalledWith(20);
87
- });
88
-
89
- it("should not update the derived chunk if the original chunk value does not change", () => {
90
- const count = chunk(5);
91
- const doubleCount = count.derive((value) => value * 2);
92
-
93
- const doubleCountSpy = jest.fn();
94
-
95
- // Subscribe to the derived chunk
96
- doubleCount.subscribe(doubleCountSpy);
97
-
98
- // Setting the same value
99
- count.set(5);
100
- expect(doubleCount.get()).toBe(10); // Derived value should remain the same
101
- expect(doubleCountSpy).toHaveBeenCalledTimes(1); // Only initial value
102
- });
103
- });
104
-
105
-
106
- test("Chunk should reset to initial value", () => {
107
- const count = chunk(5);
108
- count.set(10);
109
- expect(count.get()).toBe(10);
110
- count.reset();
111
- expect(count.get()).toBe(5);
112
- });
113
-
114
-
115
- describe('Chunk destroy', () => {
116
- const countChunk = chunk(0);
117
- const anotherChunk = chunk(0);
118
- const countCallback = jest.fn();
119
- const anotherCallback = jest.fn();
120
-
121
- beforeEach(() => {
122
- // Reset the mocks
123
- countCallback.mockClear();
124
- anotherCallback.mockClear();
125
- });
126
-
127
- it('should stop notifying subscribers after destroy is called', () => {
128
- // Subscribe to the chunks
129
- const countUnsubscribe = countChunk.subscribe(countCallback);
130
- const anotherUnsubscribe = anotherChunk.subscribe(anotherCallback);
131
-
132
- // Verify initial subscription calls
133
- expect(countCallback).toHaveBeenCalledTimes(1);
134
- expect(countCallback).toHaveBeenCalledWith(0);
135
- expect(anotherCallback).toHaveBeenCalledTimes(1);
136
- expect(anotherCallback).toHaveBeenCalledWith(0);
137
-
138
- // Clear the mocks to start fresh
139
- countCallback.mockClear();
140
- anotherCallback.mockClear();
141
-
142
- // Cleanup subscriptions before destroy
143
- countUnsubscribe();
144
- anotherUnsubscribe();
145
-
146
- // Now destroy the chunks - no warning should appear
147
- countChunk.destroy();
148
- anotherChunk.destroy();
149
-
150
- // Try setting new values after destruction
151
- countChunk.set(30);
152
- anotherChunk.set(40);
153
-
154
- // Ensure that the subscribers were not notified after destroy
155
- expect(countCallback).toHaveBeenCalledTimes(0);
156
- expect(anotherCallback).toHaveBeenCalledTimes(0);
157
- });
158
-
159
- it('should reset to initial value after destroy', () => {
160
- // Set some values
161
- countChunk.set(10);
162
- anotherChunk.set(20);
163
-
164
- // Destroy the chunks (no subscribers at this point, so no warning)
165
- countChunk.destroy();
166
- anotherChunk.destroy();
167
-
168
- // Subscribe new callbacks after destroy
169
- const newCountCallback = jest.fn();
170
- const newAnotherCallback = jest.fn();
171
-
172
- const newCountUnsubscribe = countChunk.subscribe(newCountCallback);
173
- const newAnotherUnsubscribe = anotherChunk.subscribe(newAnotherCallback);
174
-
175
- // Should receive initial values
176
- expect(newCountCallback).toHaveBeenCalledWith(0);
177
- expect(newAnotherCallback).toHaveBeenCalledWith(0);
178
-
179
- // Cleanup
180
- newCountUnsubscribe();
181
- newAnotherUnsubscribe();
182
- });
183
-
184
- // Clean up after all tests
185
- afterAll(() => {
186
- countChunk.destroy();
187
- anotherChunk.destroy();
188
- });
189
- });
@@ -1,93 +0,0 @@
1
- import { chunk } from '../src/core/core';
2
- import { computed } from '../src/core/computed';
3
-
4
- describe('computed', () => {
5
- it('should compute the value based on dependencies', () => {
6
- const num1 = chunk(2);
7
- const num2 = chunk(3);
8
-
9
- const sum = computed([num1, num2], (a, b) => a + b);
10
-
11
- expect(sum.get()).toBe(5);
12
- });
13
-
14
- it('should recompute when a dependency changes', () => {
15
- const num1 = chunk(4);
16
- const num2 = chunk(5);
17
-
18
- const product = computed([num1, num2], (a, b) => a * b);
19
-
20
- expect(product.get()).toBe(20);
21
-
22
- num1.set(10);
23
-
24
- // Trigger recomputation
25
- expect(product.get()).toBe(50);
26
- });
27
-
28
- it('should cache the computed value until a dependency changes', () => {
29
- const num1 = chunk(1);
30
- const num2 = chunk(2);
31
-
32
- const sum = computed([num1, num2], (a, b) => a + b);
33
-
34
- const initialValue = sum.get();
35
- expect(initialValue).toBe(3);
36
-
37
- num1.set(1); // Setting to the same value, should not trigger recompute
38
- const cachedValue = sum.get();
39
- expect(cachedValue).toBe(3); // Cached value should be returned
40
- });
41
-
42
- it('should mark as dirty when a dependency changes', () => {
43
- const num1 = chunk(7);
44
- const num2 = chunk(8);
45
-
46
- const diff = computed([num1, num2], (a, b) => b - a);
47
-
48
- expect(diff.isDirty()).toBe(false);
49
-
50
- num2.set(10);
51
-
52
- expect(diff.isDirty()).toBe(true);
53
- });
54
-
55
- it('should throw error when attempting to set computed value', () => {
56
- const num1 = chunk(10);
57
- const num2 = chunk(20);
58
-
59
- const sum = computed([num1, num2], (a, b) => a + b);
60
-
61
- expect(() => sum.set(100)).toThrow('Cannot directly set a computed value');
62
- });
63
-
64
- it('should manually recompute the value', () => {
65
- const num1 = chunk(1);
66
- const num2 = chunk(2);
67
-
68
- const sum = computed([num1, num2], (a, b) => a + b);
69
-
70
- expect(sum.get()).toBe(3);
71
-
72
- num1.set(4);
73
- expect(sum.isDirty()).toBe(true);
74
-
75
- sum.recompute(); // Manually recompute
76
- expect(sum.get()).toBe(6);
77
- expect(sum.isDirty()).toBe(false);
78
- });
79
-
80
- it('should support multiple dependencies', () => {
81
- const a = chunk(2);
82
- const b = chunk(3);
83
- const c = chunk(4);
84
-
85
- const result = computed([a, b, c], (x, y, z) => x * y + z);
86
-
87
- expect(result.get()).toBe(10);
88
-
89
- b.set(5);
90
-
91
- expect(result.get()).toBe(14);
92
- });
93
- });
@@ -1,99 +0,0 @@
1
- import { chunk } from "../src/core/core";
2
- import { withHistory } from "../src/middleware/history";
3
-
4
-
5
- describe('Chunk with History', () => {
6
- it('should maintain history of changes', () => {
7
- const baseChunk = chunk(0);
8
- const historyChunk = withHistory(baseChunk);
9
-
10
- historyChunk.set(1);
11
- historyChunk.set(2);
12
- historyChunk.set(3);
13
-
14
- expect(historyChunk.getHistory()).toEqual([0, 1, 2, 3]);
15
- });
16
-
17
- it('should handle undo and redo operations', () => {
18
- const baseChunk = chunk(0);
19
- const historyChunk = withHistory(baseChunk);
20
- const callback = jest.fn();
21
-
22
- historyChunk.subscribe(callback);
23
- callback.mockClear(); // Clear initial subscription call
24
-
25
- historyChunk.set(1);
26
- historyChunk.set(2);
27
-
28
- expect(historyChunk.get()).toBe(2);
29
-
30
- historyChunk.undo();
31
- expect(historyChunk.get()).toBe(1);
32
-
33
- historyChunk.undo();
34
- expect(historyChunk.get()).toBe(0);
35
-
36
- historyChunk.redo();
37
- expect(historyChunk.get()).toBe(1);
38
-
39
- historyChunk.redo();
40
- expect(historyChunk.get()).toBe(2);
41
-
42
- expect(callback).toHaveBeenCalledTimes(6); // 2 sets + 2 undos + 2 redos
43
- });
44
-
45
- it('should handle branching history', () => {
46
- const baseChunk = chunk(0);
47
- const historyChunk = withHistory(baseChunk);
48
-
49
- historyChunk.set(1);
50
- historyChunk.set(2);
51
- historyChunk.undo();
52
- historyChunk.set(3); // This should create a new branch
53
-
54
- expect(historyChunk.getHistory()).toEqual([0, 1, 3]);
55
- expect(historyChunk.get()).toBe(3);
56
- });
57
-
58
- it('should respect maxHistory limit', () => {
59
- const baseChunk = chunk(0);
60
- const historyChunk = withHistory(baseChunk, { maxHistory: 3 });
61
-
62
- historyChunk.set(1);
63
- historyChunk.set(2);
64
- historyChunk.set(3);
65
- historyChunk.set(4);
66
-
67
- expect(historyChunk.getHistory()).toEqual([2, 3, 4]);
68
- });
69
-
70
- it('should handle canUndo and canRedo correctly', () => {
71
- const baseChunk = chunk(0);
72
- const historyChunk = withHistory(baseChunk);
73
-
74
- expect(historyChunk.canUndo()).toBe(false);
75
- expect(historyChunk.canRedo()).toBe(false);
76
-
77
- historyChunk.set(1);
78
- expect(historyChunk.canUndo()).toBe(true);
79
- expect(historyChunk.canRedo()).toBe(false);
80
-
81
- historyChunk.undo();
82
- expect(historyChunk.canUndo()).toBe(false);
83
- expect(historyChunk.canRedo()).toBe(true);
84
- });
85
-
86
- it('should clear history properly', () => {
87
- const baseChunk = chunk(0);
88
- const historyChunk = withHistory(baseChunk);
89
-
90
- historyChunk.set(1);
91
- historyChunk.set(2);
92
-
93
- historyChunk.clearHistory();
94
-
95
- expect(historyChunk.getHistory()).toEqual([2]);
96
- expect(historyChunk.canUndo()).toBe(false);
97
- expect(historyChunk.canRedo()).toBe(false);
98
- });
99
- });