@buley/dash 0.0.30

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 (97) hide show
  1. package/.coveralls.yml +1 -0
  2. package/.github/workflows/opencommit.yml +33 -0
  3. package/.github/workflows/testing.yml +20 -0
  4. package/.gitmodules +0 -0
  5. package/README.md +98 -0
  6. package/behaviors/cache.dev.js +282 -0
  7. package/behaviors/changes.dev.js +337 -0
  8. package/behaviors/collect.dev.js +40 -0
  9. package/behaviors/examples/async.dev.js +17 -0
  10. package/behaviors/firebase.dev.js +283 -0
  11. package/behaviors/live.dev.js +67 -0
  12. package/behaviors/map.dev.js +54 -0
  13. package/behaviors/mapreduce.dev.js +68 -0
  14. package/behaviors/match.dev.js +66 -0
  15. package/behaviors/patch.dev.js +69 -0
  16. package/behaviors/rest.dev.js +340 -0
  17. package/behaviors/shorthand.dev.js +59 -0
  18. package/behaviors/stats.dev.js +672 -0
  19. package/dist/behaviors/index.js +142 -0
  20. package/dist/database/index.js +76 -0
  21. package/dist/databases/index.js +121 -0
  22. package/dist/entry/index.js +166 -0
  23. package/dist/index.js +93 -0
  24. package/dist/indexes/index.js +153 -0
  25. package/dist/store/index.js +97 -0
  26. package/dist/stores/index.js +90 -0
  27. package/dist/utilities/index.js +174 -0
  28. package/documentation/database/closing.md +3 -0
  29. package/documentation/database/getting.md +1 -0
  30. package/documentation/database/opening.md +5 -0
  31. package/documentation/database/removing.md +3 -0
  32. package/documentation/databases.md +21 -0
  33. package/documentation/entries.md +13 -0
  34. package/documentation/entry/adding.md +1 -0
  35. package/documentation/entry/getting.md +4 -0
  36. package/documentation/entry/putting.md +0 -0
  37. package/documentation/entry/removing.md +3 -0
  38. package/documentation/entry/updating.md +0 -0
  39. package/documentation/general/security.md +10 -0
  40. package/documentation/general/transaction/requests.md +3 -0
  41. package/documentation/general/transactions.md +5 -0
  42. package/documentation/index/creating.md +1 -0
  43. package/documentation/index/getting.md +1 -0
  44. package/documentation/index/iterating.md +1 -0
  45. package/documentation/index/removing.md +1 -0
  46. package/documentation/indexes.md +3 -0
  47. package/documentation/key/cursors.md +5 -0
  48. package/documentation/key/range/bounds.md +11 -0
  49. package/documentation/key/range/direction.md +1 -0
  50. package/documentation/key/ranges.md +3 -0
  51. package/documentation/keys.md +12 -0
  52. package/documentation/objectstore/clearing.md +1 -0
  53. package/documentation/objectstore/creating.md +1 -0
  54. package/documentation/objectstore/getting.md +1 -0
  55. package/documentation/objectstore/iteration.md +1 -0
  56. package/documentation/objectstore/removing.md +1 -0
  57. package/documentation/overview.md +5 -0
  58. package/documentation/stores.md +13 -0
  59. package/jest.config.js +12 -0
  60. package/package.json +40 -0
  61. package/src/behaviors/index.ts +140 -0
  62. package/src/database/index.ts +81 -0
  63. package/src/databases/index.ts +127 -0
  64. package/src/entry/index.ts +183 -0
  65. package/src/index/index.ts +61 -0
  66. package/src/index.ts +96 -0
  67. package/src/indexes/index.ts +151 -0
  68. package/src/store/index.ts +102 -0
  69. package/src/stores/index.ts +90 -0
  70. package/src/utilities/index.ts +349 -0
  71. package/tests/behaviors/behaviors.spec.ts +123 -0
  72. package/tests/database/database.spec.ts +177 -0
  73. package/tests/databases/databases.spec.ts +199 -0
  74. package/tests/entry/entry.spec.ts +252 -0
  75. package/tests/index/index.spec.ts +94 -0
  76. package/tests/indexes/indexes.spec.ts +203 -0
  77. package/tests/store/store.spec.ts +164 -0
  78. package/tests/stores/stores.spec.ts +148 -0
  79. package/tests/utilities/clone.spec.ts +48 -0
  80. package/tests/utilities/cloneError.spec.ts +33 -0
  81. package/tests/utilities/contains.spec.ts +28 -0
  82. package/tests/utilities/exists.spec.ts +21 -0
  83. package/tests/utilities/is.spec.ts +37 -0
  84. package/tests/utilities/isArray.spec.ts +21 -0
  85. package/tests/utilities/isBoolean.spec.ts +23 -0
  86. package/tests/utilities/isEmpty.spec.ts +45 -0
  87. package/tests/utilities/isFunction.spec.ts +30 -0
  88. package/tests/utilities/isNumber.spec.ts +29 -0
  89. package/tests/utilities/isObject.spec.ts +42 -0
  90. package/tests/utilities/isRegEx.spec.ts +33 -0
  91. package/tests/utilities/isString.spec.ts +25 -0
  92. package/tests/utilities/isnt.spec.ts +50 -0
  93. package/tests/utilities/randomId.spec.ts +39 -0
  94. package/tests/utilities/safeApply.spec.ts +49 -0
  95. package/tests/utilities/safeEach.spec.ts +38 -0
  96. package/tests/utilities/safeIterate.spec.ts +47 -0
  97. package/tsconfig.json +16 -0
@@ -0,0 +1,203 @@
1
+
2
+ import indexesMethods from '../../src/indexes';
3
+ import { DashContext } from '../../src/utilities';
4
+
5
+ describe('indexesMethods', () => {
6
+ let mockSuccessCallback: jest.Mock;
7
+ let mockErrorCallback: jest.Mock;
8
+ let mockCompleteCallback: jest.Mock;
9
+
10
+ beforeEach(() => {
11
+ mockSuccessCallback = jest.fn();
12
+ mockErrorCallback = jest.fn();
13
+ mockCompleteCallback = jest.fn();
14
+ });
15
+
16
+ describe('get', () => {
17
+ it('should retrieve indexes from the object store and call on_success', async () => {
18
+ const mockObjectStore = {
19
+ indexNames: ['index1', 'index2']
20
+ };
21
+
22
+ const get_ctx: DashContext = {
23
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
24
+ on_success: mockSuccessCallback
25
+ };
26
+
27
+ await indexesMethods.get(get_ctx);
28
+
29
+ expect(get_ctx.indexes).toEqual(['index1', 'index2']);
30
+ expect(mockSuccessCallback).toHaveBeenCalledWith(get_ctx);
31
+ });
32
+ });
33
+
34
+ describe('add', () => {
35
+ it('should add an index to the object store and call on_success', async () => {
36
+ const mockObjectStore = {
37
+ createIndex: jest.fn()
38
+ };
39
+
40
+ const add_ctx: DashContext = {
41
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
42
+ index: 'newIndex',
43
+ index_key_path: 'keyPath',
44
+ index_unique: true,
45
+ on_success: mockSuccessCallback
46
+ };
47
+
48
+ await indexesMethods.add(add_ctx);
49
+
50
+ expect(mockObjectStore.createIndex).toHaveBeenCalledWith('newIndex', 'keyPath', {
51
+ unique: true,
52
+ multiEntry: false
53
+ });
54
+ expect(mockSuccessCallback).toHaveBeenCalledWith(add_ctx);
55
+ });
56
+ });
57
+
58
+ describe('remove', () => {
59
+ it('should remove an index from the object store and call on_success', async () => {
60
+ const mockObjectStore = {
61
+ deleteIndex: jest.fn()
62
+ };
63
+
64
+ const remove_ctx: DashContext = {
65
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
66
+ index: 'indexToRemove',
67
+ on_success: mockSuccessCallback
68
+ };
69
+
70
+ await indexesMethods.remove(remove_ctx);
71
+
72
+ expect(mockObjectStore.deleteIndex).toHaveBeenCalledWith('indexToRemove');
73
+ expect(mockSuccessCallback).toHaveBeenCalledWith(remove_ctx);
74
+ });
75
+ });
76
+
77
+ describe('getEntries', () => {
78
+ it('should retrieve entries from an index and call on_success for each entry and on_complete at the end', async () => {
79
+ jest.setTimeout(10000); // Increase timeout to 10 seconds
80
+
81
+ let callCount = 0;
82
+ const mockEntries = [
83
+ { id: 1, name: 'Entry1' },
84
+ { id: 2, name: 'Entry2' }
85
+ ];
86
+
87
+ const mockCursor = {
88
+ value: mockEntries[0],
89
+ continue: jest.fn(() => {
90
+ callCount++;
91
+ if (callCount >= mockEntries.length) {
92
+ mockRequest.result = null; // Simulate end of the cursor
93
+ } else {
94
+ mockCursor.value = mockEntries[callCount];
95
+ }
96
+ mockRequest.onsuccess(new Event('success'));
97
+ }),
98
+ };
99
+
100
+ const mockRequest = {
101
+ result: mockCursor as { value: { id: number; name: string; }; continue: jest.Mock<void, [], any>; } | null,
102
+ onsuccess: (ev: Event) => {
103
+ // your code here
104
+ },
105
+ };
106
+
107
+ const mockObjectStore = {
108
+ index: jest.fn(() => ({
109
+ openCursor: jest.fn(() => mockRequest),
110
+ })),
111
+ };
112
+
113
+ const mockSuccessCallback = jest.fn();
114
+ const mockCompleteCallback = jest.fn();
115
+
116
+ const get_ctx: DashContext = {
117
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
118
+ index: 'indexName',
119
+ on_success: mockSuccessCallback,
120
+ on_complete: mockCompleteCallback,
121
+ };
122
+
123
+ const getEntriesPromise = indexesMethods.getEntries(get_ctx);
124
+
125
+ // Trigger the first onsuccess callback
126
+ if (mockRequest.onsuccess) {
127
+ mockRequest.onsuccess(new Event('success'));
128
+ }
129
+
130
+ await getEntriesPromise;
131
+
132
+ expect(mockObjectStore.index).toHaveBeenCalledWith('indexName');
133
+ expect(mockSuccessCallback).toHaveBeenCalledTimes(2); // Called for two entries
134
+ expect(mockSuccessCallback).toHaveBeenNthCalledWith(1, mockEntries[0]);
135
+ expect(mockSuccessCallback).toHaveBeenNthCalledWith(2, mockEntries[1]);
136
+ expect(mockCompleteCallback).toHaveBeenCalledWith(get_ctx);
137
+ });
138
+
139
+ });
140
+
141
+ describe('countEntries', () => {
142
+ it('should count entries in the object store index and call on_success', async () => {
143
+ const mockObjectStore = {
144
+ index: jest.fn().mockReturnValue({
145
+ count: jest.fn().mockReturnValue({
146
+ addEventListener: (event: string, callback: () => void) => {
147
+ if (event === 'success') callback();
148
+ },
149
+ result: 5
150
+ })
151
+ })
152
+ };
153
+
154
+ const count_ctx: DashContext = {
155
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
156
+ index: 'testIndex',
157
+ on_success: mockSuccessCallback
158
+ };
159
+
160
+ await indexesMethods.countEntries(count_ctx);
161
+
162
+ expect(mockObjectStore.index).toHaveBeenCalledWith('testIndex');
163
+ expect(mockSuccessCallback).toHaveBeenCalledWith(count_ctx);
164
+ expect(count_ctx.total).toBe(5);
165
+ });
166
+
167
+
168
+ it('should handle errors and call on_error', async () => {
169
+ const mockObjectStore = {
170
+ index: jest.fn().mockReturnValue({
171
+ count: jest.fn().mockReturnValue({
172
+ addEventListener: (event: string, callback: (event: any) => void) => {
173
+ if (event === 'error') {
174
+ const mockErrorEvent = { target: { error: new Error('Test Error') } };
175
+ callback(mockErrorEvent);
176
+ }
177
+ }
178
+ })
179
+ })
180
+ };
181
+
182
+ const count_ctx: DashContext = {
183
+ objectstore: mockObjectStore as unknown as IDBObjectStore,
184
+ index: 'testIndex',
185
+ on_error: mockErrorCallback
186
+ };
187
+
188
+ try {
189
+ // Await the function call
190
+ await indexesMethods.countEntries(count_ctx);
191
+ } catch (ctx: any) {
192
+ // Expect the error to be part of the returned context
193
+ expect(ctx.error).toEqual(new Error('Test Error'));
194
+
195
+ // Ensure the error callback is called with the correct context
196
+ expect(mockErrorCallback).toHaveBeenCalledWith(count_ctx);
197
+ }
198
+ });
199
+
200
+
201
+ });
202
+
203
+ });
@@ -0,0 +1,164 @@
1
+
2
+ import storeMethods from '../../src/store';
3
+ import { DashContext } from '../../src/utilities';
4
+
5
+ describe('storeMethods', () => {
6
+ // Mock functions to be used in tests
7
+ const mockSuccessCallback = jest.fn();
8
+ const mockErrorCallback = jest.fn();
9
+
10
+ beforeEach(() => {
11
+ // Reset mock functions before each test
12
+ mockSuccessCallback.mockReset();
13
+ mockErrorCallback.mockReset();
14
+ });
15
+
16
+ describe('clear', () => {
17
+ it('should clear the object store and call on_success', async () => {
18
+ const mockRequest = {
19
+ addEventListener: jest.fn((event, callback) => {
20
+ if (event === 'success') {
21
+ setTimeout(() => {
22
+ callback();
23
+ }, 0); // Simulate async success event
24
+ }
25
+ }),
26
+ };
27
+
28
+ const clear_ctx: DashContext = {
29
+ objectstore: {
30
+ clear: jest.fn(() => mockRequest),
31
+ } as unknown as IDBObjectStore,
32
+ on_success: mockSuccessCallback,
33
+ };
34
+
35
+ await storeMethods.clear(clear_ctx);
36
+ expect(clear_ctx.objectstore?.clear).toHaveBeenCalled();
37
+ expect(mockSuccessCallback).toHaveBeenCalledWith(clear_ctx);
38
+ });
39
+
40
+
41
+ it('should handle errors when clearing the object store', () => {
42
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
43
+ if (event === 'error') (callback as EventListener)({ target: { error: new Error('Clear Error') } } as any);
44
+ }) };
45
+
46
+ const clear_ctx: DashContext = {
47
+ objectstore: {
48
+ clear: jest.fn(() => mockRequest),
49
+ } as unknown as IDBObjectStore,
50
+ on_error: mockErrorCallback,
51
+ };
52
+
53
+ return storeMethods.clear(clear_ctx).catch((ctx: DashContext) => {
54
+ expect(clear_ctx.objectstore?.clear).toHaveBeenCalled();
55
+ expect(mockErrorCallback).toHaveBeenCalledWith(ctx);
56
+ expect(ctx.error.message).toBe('Clear Error');
57
+ });
58
+ });
59
+ });
60
+
61
+ describe('remove', () => {
62
+ it('should remove an entry from the object store and call on_success', () => {
63
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
64
+ if (event === 'success') (callback as EventListener)(new Event('success'));
65
+ }) };
66
+
67
+ const remove_ctx: DashContext = {
68
+ objectstore: {
69
+ delete: jest.fn(() => mockRequest),
70
+ } as unknown as IDBObjectStore,
71
+ key: 'testKey',
72
+ on_success: mockSuccessCallback,
73
+ };
74
+
75
+ return storeMethods.remove(remove_ctx).then((ctx: DashContext) => {
76
+ expect(remove_ctx.objectstore?.delete).toHaveBeenCalledWith('testKey');
77
+ expect(mockSuccessCallback).toHaveBeenCalledWith(ctx);
78
+ });
79
+ });
80
+
81
+ it('should handle errors when removing an entry', () => {
82
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
83
+ if (event === 'error') (callback as EventListener)({ target: { error: new Error('Remove Error') } } as any);
84
+ }) };
85
+
86
+ const remove_ctx: DashContext = {
87
+ objectstore: {
88
+ delete: jest.fn(() => mockRequest),
89
+ } as unknown as IDBObjectStore,
90
+ key: 'testKey',
91
+ on_error: mockErrorCallback,
92
+ };
93
+
94
+ return storeMethods.remove(remove_ctx).catch((ctx: DashContext) => {
95
+ expect(remove_ctx.objectstore?.delete).toHaveBeenCalledWith('testKey');
96
+ expect(mockErrorCallback).toHaveBeenCalledWith(ctx);
97
+ expect(ctx.error.message).toBe('Remove Error');
98
+ });
99
+ });
100
+ });
101
+
102
+ describe('get', () => {
103
+ it('should retrieve an entry from the object store and call on_success', () => {
104
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
105
+ if (event === 'success') (callback as EventListener)(new Event('success'));
106
+ }), result: 'testEntry' };
107
+
108
+ const get_ctx: DashContext = {
109
+ objectstore: {
110
+ get: jest.fn(() => mockRequest),
111
+ } as unknown as IDBObjectStore,
112
+ key: 'testKey',
113
+ on_success: mockSuccessCallback,
114
+ };
115
+
116
+ return storeMethods.get(get_ctx).then((ctx: DashContext) => {
117
+ expect(get_ctx.objectstore?.get).toHaveBeenCalledWith('testKey');
118
+ expect(mockSuccessCallback).toHaveBeenCalledWith(ctx);
119
+ expect(ctx.entry).toBe('testEntry');
120
+ });
121
+ });
122
+
123
+ it('should handle errors when retrieving an entry', () => {
124
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
125
+ if (event === 'error') (callback as EventListener)({ target: { error: new Error('Get Error') } } as any);
126
+ }) };
127
+
128
+ const get_ctx: DashContext = {
129
+ objectstore: {
130
+ get: jest.fn(() => mockRequest),
131
+ } as unknown as IDBObjectStore,
132
+ key: 'testKey',
133
+ on_error: mockErrorCallback,
134
+ };
135
+
136
+ return storeMethods.get(get_ctx).catch((ctx: DashContext) => {
137
+ expect(get_ctx.objectstore?.get).toHaveBeenCalledWith('testKey');
138
+ expect(mockErrorCallback).toHaveBeenCalledWith(ctx);
139
+ expect(ctx.error.message).toBe('Get Error');
140
+ });
141
+ });
142
+
143
+ it('should reject if the entry is missing', () => {
144
+ const mockRequest = { addEventListener: jest.fn((event: string, callback: EventListenerOrEventListenerObject) => {
145
+ if (event === 'success') (callback as EventListener)(new Event('success'));
146
+ }), result: undefined };
147
+
148
+ const get_ctx: DashContext = {
149
+ objectstore: {
150
+ get: jest.fn(() => mockRequest),
151
+ } as unknown as IDBObjectStore,
152
+ key: 'testKey',
153
+ on_error: mockErrorCallback,
154
+ };
155
+
156
+ return storeMethods.get(get_ctx).catch((ctx: DashContext) => {
157
+ expect(get_ctx.objectstore?.get).toHaveBeenCalledWith('testKey');
158
+ expect(mockErrorCallback).toHaveBeenCalledWith(ctx);
159
+ expect(ctx.error.message).toBe('missing');
160
+ expect(ctx.error.name).toBe('DashNoEntry');
161
+ });
162
+ });
163
+ });
164
+ });
@@ -0,0 +1,148 @@
1
+
2
+ import storesMethods from '../../src/stores';
3
+ import { DashContext } from '../../src/utilities';
4
+
5
+ describe('storesMethods', () => {
6
+ // Mock functions to be used in tests
7
+ const mockSuccessCallback = jest.fn();
8
+ const mockErrorCallback = jest.fn();
9
+
10
+ beforeEach(() => {
11
+ // Reset mock functions before each test
12
+ mockSuccessCallback.mockReset();
13
+ mockErrorCallback.mockReset();
14
+ });
15
+
16
+ const mockDb = {
17
+ name: 'mockDb',
18
+ version: 1,
19
+ objectStoreNames: ['store1', 'store2'],
20
+ createObjectStore: jest.fn(() => ({
21
+ createIndex: jest.fn(),
22
+ })),
23
+ deleteObjectStore: jest.fn(),
24
+ transaction: jest.fn(() => ({
25
+ objectStore: jest.fn(() => ({
26
+ clear: jest.fn(),
27
+ })),
28
+ db: {},
29
+ mode: 'readwrite',
30
+ error: null,
31
+ onabort: null,
32
+ oncomplete: null,
33
+ onerror: null,
34
+ addEventListener: jest.fn(),
35
+ removeEventListener: jest.fn(),
36
+ dispatchEvent: jest.fn(),
37
+ })),
38
+ close: jest.fn(),
39
+ onabort: null,
40
+ onclose: null,
41
+ onerror: null,
42
+ onversionchange: null,
43
+ } as unknown as IDBDatabase;
44
+
45
+
46
+ describe('get', () => {
47
+ it('should retrieve object store names and call on_success', () => {
48
+ const get_ctx: DashContext = { db: mockDb, on_success: mockSuccessCallback };
49
+
50
+ storesMethods.get(get_ctx);
51
+
52
+ expect(get_ctx.stores).toEqual(['store1', 'store2']); // Check store names
53
+ expect(mockSuccessCallback).toHaveBeenCalledWith(get_ctx); // Success callback should be called
54
+ });
55
+ });
56
+
57
+ describe('add', () => {
58
+ it('should add a new object store and call on_success', () => {
59
+ const mockRequest = {
60
+ result: {
61
+ createObjectStore: jest.fn(() => ({
62
+ createIndex: jest.fn(),
63
+ })),
64
+ },
65
+ } as IDBRequest<any>;
66
+
67
+ const add_ctx: DashContext = {
68
+ request: mockRequest, // Mock the request object and its result
69
+ store: 'newStore',
70
+ store_key_path: 'id',
71
+ auto_increment: true,
72
+ indexes: [{ name: 'index1', keyPath: 'key1', unique: true }],
73
+ on_success: mockSuccessCallback,
74
+ };
75
+
76
+ storesMethods.add(add_ctx);
77
+
78
+ expect(mockRequest.result.createObjectStore).toHaveBeenCalledWith('newStore', { keyPath: 'id', autoIncrement: true });
79
+ expect(mockSuccessCallback).toHaveBeenCalledWith(add_ctx); // Success callback should be called
80
+ });
81
+
82
+ it('should throw an error if database is undefined', () => {
83
+ const add_ctx: DashContext = { db: undefined, on_error: mockErrorCallback };
84
+
85
+ expect(() => storesMethods.add(add_ctx)).toThrow('Database is undefined');
86
+ });
87
+ });
88
+
89
+ describe('remove', () => {
90
+ it('should remove an object store and call on_success', () => {
91
+ const remove_ctx: DashContext = { db: mockDb, store: 'storeToRemove', on_success: mockSuccessCallback };
92
+
93
+ storesMethods.remove(remove_ctx);
94
+
95
+ expect(mockDb.deleteObjectStore).toHaveBeenCalledWith('storeToRemove');
96
+ expect(mockSuccessCallback).toHaveBeenCalledWith(remove_ctx); // Success callback should be called
97
+ });
98
+ });
99
+
100
+ describe('clearAll', () => {
101
+ it('should clear all object stores and call on_success on transaction complete', () => {
102
+ const mockTransaction = {
103
+ objectStore: jest.fn(() => ({
104
+ clear: jest.fn(),
105
+ })),
106
+ addEventListener: jest.fn((event, callback) => {
107
+ if (event === 'complete') callback(); // Trigger complete event
108
+ }),
109
+ oncomplete: jest.fn(),
110
+ };
111
+
112
+ const mockDb = {
113
+ name: 'mockDb',
114
+ objectStoreNames: ['store1', 'store2'],
115
+ transaction: jest.fn(() => mockTransaction),
116
+ createObjectStore: jest.fn(),
117
+ deleteObjectStore: jest.fn(),
118
+ } as unknown as IDBDatabase;
119
+
120
+ const clear_ctx: DashContext = { db: mockDb, on_success: mockSuccessCallback, on_error: mockErrorCallback };
121
+
122
+ storesMethods.clearAll(clear_ctx);
123
+
124
+ expect(mockDb.transaction).toHaveBeenCalledWith(['store1', 'store2'], 'readwrite');
125
+ expect(mockSuccessCallback).toHaveBeenCalledWith(clear_ctx); // Success callback should be called
126
+ });
127
+
128
+ it('should call on_error when transaction encounters an error', () => {
129
+ const failingMockDb: unknown = {
130
+ ...mockDb,
131
+ transaction: jest.fn(() => ({
132
+ objectStore: jest.fn(() => ({
133
+ clear: jest.fn(),
134
+ })),
135
+ addEventListener: jest.fn((event, callback) => {
136
+ if (event === 'error') callback({ target: { error: new Error('Transaction Error') } });
137
+ }),
138
+ })),
139
+ };
140
+ const clear_ctx: DashContext = { db: failingMockDb as IDBDatabase, on_success: mockSuccessCallback, on_error: mockErrorCallback };
141
+
142
+ storesMethods.clearAll(clear_ctx);
143
+
144
+ expect(mockErrorCallback).toHaveBeenCalled(); // Error callback should be called
145
+ expect(clear_ctx.error.message).toBe('Transaction Error');
146
+ });
147
+ });
148
+ });
@@ -0,0 +1,48 @@
1
+ import { clone } from '../../src/utilities';
2
+
3
+ describe('clone', () => {
4
+ it('should clone a simple object', () => {
5
+ const result = clone({ foo: "bar" });
6
+ expect(result).toBeDefined();
7
+ expect(result).toEqual({ foo: "bar" });
8
+ expect(result).not.toBe({ foo: "bar" }); // Ensure it's not the same reference
9
+ });
10
+
11
+ it('should deeply clone a nested object', () => {
12
+ const source = { foo: "bar", nested: { baz: 42 } };
13
+ const result = clone(source);
14
+ expect(result).toEqual(source);
15
+ expect(result).not.toBe(source); // Different reference
16
+ expect(result.nested).not.toBe(source.nested); // Nested object should also be cloned
17
+ });
18
+
19
+ it('should clone arrays correctly', () => {
20
+ const source = [1, 2, 3, { foo: "bar" }];
21
+ const result = clone(source);
22
+ expect(result).toEqual(source);
23
+ expect(result).not.toBe(source); // Ensure it's not the same reference
24
+ expect(result[3]).not.toBe(source[3]); // Nested objects in arrays should also be cloned
25
+ });
26
+
27
+ it('should handle cloning null', () => {
28
+ const result = clone(null);
29
+ expect(result).toBeNull();
30
+ });
31
+
32
+ it('should handle cloning undefined', () => {
33
+ const result = clone(undefined);
34
+ expect(result).toBeUndefined();
35
+ });
36
+
37
+ it('should handle cloning complex objects with functions', () => {
38
+ const source = {
39
+ foo: "bar",
40
+ method: function () {
41
+ return "test";
42
+ }
43
+ };
44
+ const result = clone(source);
45
+ expect(result).toEqual(source);
46
+ expect(result.method()).toBe("test"); // Functions should still work after cloning
47
+ });
48
+ });
@@ -0,0 +1,33 @@
1
+ import { cloneError } from '../../src/utilities';
2
+
3
+ describe('cloneError', () => {
4
+ it('should create a deep clone of an error object', () => {
5
+ const source = new Error('test');
6
+ const result = cloneError(source);
7
+
8
+ // Check that the result is defined and an instance of Error
9
+ expect(result).toBeDefined();
10
+ expect(result).toBeInstanceOf(Error);
11
+
12
+ // Ensure the cloned error has the same message and properties
13
+ expect(result.message).toBe(source.message);
14
+
15
+ // Optionally verify the stack if it's available
16
+ if (source.stack) {
17
+ expect(result.stack).toBe(source.stack); // Stack should be the same
18
+ }
19
+
20
+ // Ensure the result is a new object, not just a reference to the original
21
+ expect(result).not.toBe(source);
22
+ });
23
+
24
+ it('should handle custom error properties', () => {
25
+ const source = new Error('test') as any;
26
+ source.customProp = 'customValue';
27
+ const result = cloneError(source);
28
+
29
+ // Ensure the custom properties are cloned as well
30
+ expect((result as any).customProp).toBe(source.customProp);
31
+ expect(result).not.toBe(source); // Verify it's a new object
32
+ });
33
+ });
@@ -0,0 +1,28 @@
1
+ import { contains } from '../../src/utilities';
2
+
3
+ describe('contains', () => {
4
+ it('should return true if the substring exists in the string', () => {
5
+ const result = contains('hello world', 'world');
6
+ expect(result).toBe(true);
7
+ });
8
+
9
+ it('should return false if the substring does not exist in the string', () => {
10
+ const result = contains('hello world', 'moon');
11
+ expect(result).toBe(false);
12
+ });
13
+
14
+ it('should return false when the main string is empty', () => {
15
+ const result = contains('', 'hello');
16
+ expect(result).toBe(false);
17
+ });
18
+
19
+ it('should return true when the substring is empty', () => {
20
+ const result = contains('hello world', '');
21
+ expect(result).toBe(true); // An empty substring is technically in any string
22
+ });
23
+
24
+ it('should handle case sensitivity properly', () => {
25
+ const result = contains('hello world', 'World');
26
+ expect(result).toBe(false); // Case-sensitive
27
+ });
28
+ });
@@ -0,0 +1,21 @@
1
+ import { exists } from '../../src/utilities';
2
+
3
+ describe('exists', () => {
4
+ it('should return true for defined values', () => {
5
+ expect(exists(42)).toBe(true); // number
6
+ expect(exists('hello')).toBe(true); // non-empty string
7
+ expect(exists({})).toBe(true); // object
8
+ expect(exists([])).toBe(true); // array
9
+ expect(exists(false)).toBe(true); // boolean false
10
+ expect(exists(0)).toBe(true); // number 0
11
+ });
12
+
13
+ it('should return false for undefined or null values', () => {
14
+ expect(exists(undefined)).toBe(false); // undefined
15
+ expect(exists(null)).toBe(false); // null
16
+ });
17
+
18
+ it('should return true for empty string', () => {
19
+ expect(exists('')).toBe(true); // empty string is still a defined value
20
+ });
21
+ });
@@ -0,0 +1,37 @@
1
+ import { is } from '../../src/utilities';
2
+
3
+ describe('is', () => {
4
+ it('should return true for identical primitive values', () => {
5
+ expect(is(42, 42)).toBe(true); // number
6
+ expect(is('hello', 'hello')).toBe(true); // string
7
+ expect(is(true, true)).toBe(true); // boolean
8
+ });
9
+
10
+ it('should return true for objects with the same reference', () => {
11
+ const obj = { foo: 'bar' };
12
+ expect(is(obj, obj)).toBe(true); // Same reference
13
+ });
14
+
15
+ it('should return false for different objects even if they have the same structure', () => {
16
+ const obj1 = { foo: 'bar' };
17
+ const obj2 = { foo: 'bar' };
18
+ expect(is(obj1, obj2)).toBe(false); // Different references
19
+ });
20
+
21
+ it('should return true for identical arrays (by reference)', () => {
22
+ const arr = [1, 2, 3];
23
+ expect(is(arr, arr)).toBe(true); // Same array reference
24
+ });
25
+
26
+ it('should return false for different arrays with the same elements', () => {
27
+ expect(is([1, 2, 3], [1, 2, 3])).toBe(false); // Different array instances
28
+ });
29
+
30
+ it('should return true for null values compared to null', () => {
31
+ expect(is(null, null)).toBe(true); // null values
32
+ });
33
+
34
+ it('should return false when comparing null with undefined', () => {
35
+ expect(is(null, undefined)).toBe(false); // null vs undefined
36
+ });
37
+ });