@aiao/rxdb-react 0.0.8 → 0.0.10

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiao/rxdb-react",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -15,8 +15,8 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@aiao/rxdb": "0.0.8",
19
- "@aiao/utils": "0.0.8"
18
+ "@aiao/rxdb": "0.0.10",
19
+ "@aiao/utils": "0.0.10"
20
20
  },
21
21
  "nx": {
22
22
  "name": "rxdb-react",
package/src/hooks.spec.ts CHANGED
@@ -1,6 +1,20 @@
1
- import { of } from 'rxjs';
1
+ import { of, Subject, throwError } from 'rxjs';
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { useFind, useFindOne, useGet } from './hooks';
3
+ import {
4
+ useCount,
5
+ useCountAncestors,
6
+ useCountDescendants,
7
+ useCountNeighbors,
8
+ useFind,
9
+ useFindAll,
10
+ useFindAncestors,
11
+ useFindDescendants,
12
+ useFindOne,
13
+ useFindOneOrFail,
14
+ useGet,
15
+ useGraphNeighbors,
16
+ useGraphPaths
17
+ } from './hooks';
4
18
 
5
19
  // Mock React hooks
6
20
  let mockState: any[] = [];
@@ -32,7 +46,17 @@ class MockEntity {
32
46
  name!: string;
33
47
  static get = vi.fn();
34
48
  static findOne = vi.fn();
49
+ static findOneOrFail = vi.fn();
35
50
  static find = vi.fn();
51
+ static findAll = vi.fn();
52
+ static count = vi.fn();
53
+ static findDescendants = vi.fn();
54
+ static countDescendants = vi.fn();
55
+ static findAncestors = vi.fn();
56
+ static countAncestors = vi.fn();
57
+ static findNeighbors = vi.fn();
58
+ static countNeighbors = vi.fn();
59
+ static findPaths = vi.fn();
36
60
  }
37
61
 
38
62
  describe('useGet', () => {
@@ -124,4 +148,254 @@ describe('Hook cleanup', () => {
124
148
 
125
149
  expect(mockEffectCleanups.length).toBeGreaterThan(0);
126
150
  });
151
+
152
+ it('should unsubscribe on cleanup', () => {
153
+ const mockUnsubscribe = vi.fn();
154
+ const mockSubscription = { unsubscribe: mockUnsubscribe };
155
+ const subject = new Subject();
156
+ MockEntity.get.mockReturnValue(subject.asObservable());
157
+ (subject.subscribe as any) = vi.fn(() => mockSubscription);
158
+
159
+ MockEntity.get.mockReturnValue({
160
+ subscribe: vi.fn(() => mockSubscription)
161
+ });
162
+
163
+ useGet(MockEntity as any, '1');
164
+
165
+ // Execute cleanup
166
+ mockEffectCleanups.forEach(cleanup => cleanup());
167
+
168
+ expect(mockUnsubscribe).toHaveBeenCalled();
169
+ });
170
+
171
+ it('should clean up previous subscription on re-render', () => {
172
+ const mockUnsubscribe = vi.fn();
173
+ const mockSubscription = { unsubscribe: mockUnsubscribe };
174
+
175
+ MockEntity.get.mockReturnValue({
176
+ subscribe: vi.fn(() => mockSubscription)
177
+ });
178
+
179
+ // First render
180
+ useGet(MockEntity as any, '1');
181
+
182
+ // Simulate re-render by calling effect again (the effect will clean up previous subscription)
183
+ mockState = [];
184
+ mockStateIndex = 0;
185
+
186
+ // Second render - this should trigger cleanup of previous subscription
187
+ useGet(MockEntity as any, '2');
188
+
189
+ // The cleanup from first render should have been called
190
+ expect(mockEffectCleanups.length).toBeGreaterThan(0);
191
+ });
192
+ });
193
+
194
+ describe('Error handling', () => {
195
+ beforeEach(() => {
196
+ vi.clearAllMocks();
197
+ mockState = [];
198
+ mockStateIndex = 0;
199
+ mockEffectCleanups = [];
200
+ });
201
+
202
+ it('should handle method not found error', async () => {
203
+ // Use a mock entity without the method
204
+ const NoMethodEntity = {} as any;
205
+
206
+ const result = useGet(NoMethodEntity, '1');
207
+
208
+ // Wait for Promise.resolve to complete
209
+ await new Promise(resolve => setTimeout(resolve, 0));
210
+
211
+ expect(result).toBeDefined();
212
+ });
213
+
214
+ it('should handle subscription error', () => {
215
+ const testError = new Error('Test error');
216
+ MockEntity.get.mockReturnValue(throwError(() => testError));
217
+
218
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
219
+
220
+ const result = useGet(MockEntity as any, '1');
221
+
222
+ expect(result).toBeDefined();
223
+ consoleSpy.mockRestore();
224
+ });
225
+
226
+ it('should handle exception during query execution', () => {
227
+ MockEntity.get.mockImplementation(() => {
228
+ throw new Error('Sync error');
229
+ });
230
+
231
+ const result = useGet(MockEntity as any, '1');
232
+
233
+ expect(result).toBeDefined();
234
+ });
235
+ });
236
+
237
+ describe('isEmpty behavior', () => {
238
+ beforeEach(() => {
239
+ vi.clearAllMocks();
240
+ mockState = [];
241
+ mockStateIndex = 0;
242
+ mockEffectCleanups = [];
243
+ });
244
+
245
+ it('should set isEmpty true for empty array', () => {
246
+ MockEntity.find.mockReturnValue(of([]));
247
+
248
+ const result = useFind(MockEntity as any, {});
249
+
250
+ expect(result).toBeDefined();
251
+ });
252
+
253
+ it('should set isEmpty false for non-empty array', () => {
254
+ MockEntity.find.mockReturnValue(of([{ id: '1' }]));
255
+
256
+ const result = useFind(MockEntity as any, {});
257
+
258
+ expect(result).toBeDefined();
259
+ });
260
+
261
+ it('should set isEmpty true for null value', () => {
262
+ MockEntity.findOne.mockReturnValue(of(null));
263
+
264
+ const result = useFindOne(MockEntity as any, {});
265
+
266
+ expect(result).toBeDefined();
267
+ });
268
+
269
+ it('should set isEmpty false for non-null value', () => {
270
+ MockEntity.findOne.mockReturnValue(of({ id: '1' }));
271
+
272
+ const result = useFindOne(MockEntity as any, {});
273
+
274
+ expect(result).toBeDefined();
275
+ });
276
+ });
277
+
278
+ describe('useFindOneOrFail', () => {
279
+ beforeEach(() => {
280
+ vi.clearAllMocks();
281
+ mockState = [];
282
+ mockStateIndex = 0;
283
+ mockEffectCleanups = [];
284
+ });
285
+
286
+ it('should call findOneOrFail method', () => {
287
+ MockEntity.findOneOrFail.mockReturnValue(of({ id: '1', name: 'Found' }));
288
+
289
+ useFindOneOrFail(MockEntity as any, { where: { id: '1' } });
290
+
291
+ expect(MockEntity.findOneOrFail).toHaveBeenCalledWith({ where: { id: '1' } });
292
+ });
293
+ });
294
+
295
+ describe('useFindAll', () => {
296
+ beforeEach(() => {
297
+ vi.clearAllMocks();
298
+ mockState = [];
299
+ mockStateIndex = 0;
300
+ mockEffectCleanups = [];
301
+ });
302
+
303
+ it('should call findAll method', () => {
304
+ MockEntity.findAll.mockReturnValue(of([{ id: '1' }, { id: '2' }]));
305
+
306
+ useFindAll(MockEntity as any, {});
307
+
308
+ expect(MockEntity.findAll).toHaveBeenCalled();
309
+ });
310
+ });
311
+
312
+ describe('useCount', () => {
313
+ beforeEach(() => {
314
+ vi.clearAllMocks();
315
+ mockState = [];
316
+ mockStateIndex = 0;
317
+ mockEffectCleanups = [];
318
+ });
319
+
320
+ it('should call count method', () => {
321
+ MockEntity.count.mockReturnValue(of(5));
322
+
323
+ useCount(MockEntity as any, {});
324
+
325
+ expect(MockEntity.count).toHaveBeenCalled();
326
+ });
327
+ });
328
+
329
+ describe('Tree Repository Hooks', () => {
330
+ beforeEach(() => {
331
+ vi.clearAllMocks();
332
+ mockState = [];
333
+ mockStateIndex = 0;
334
+ mockEffectCleanups = [];
335
+ });
336
+
337
+ it('useFindDescendants should call findDescendants', () => {
338
+ MockEntity.findDescendants.mockReturnValue(of([{ id: '2' }]));
339
+
340
+ useFindDescendants(MockEntity as any, { entityId: '1' });
341
+
342
+ expect(MockEntity.findDescendants).toHaveBeenCalledWith({ entityId: '1' });
343
+ });
344
+
345
+ it('useCountDescendants should call countDescendants', () => {
346
+ MockEntity.countDescendants.mockReturnValue(of(3));
347
+
348
+ useCountDescendants(MockEntity as any, { entityId: '1' });
349
+
350
+ expect(MockEntity.countDescendants).toHaveBeenCalledWith({ entityId: '1' });
351
+ });
352
+
353
+ it('useFindAncestors should call findAncestors', () => {
354
+ MockEntity.findAncestors.mockReturnValue(of([{ id: '0' }]));
355
+
356
+ useFindAncestors(MockEntity as any, { entityId: '1' });
357
+
358
+ expect(MockEntity.findAncestors).toHaveBeenCalledWith({ entityId: '1' });
359
+ });
360
+
361
+ it('useCountAncestors should call countAncestors', () => {
362
+ MockEntity.countAncestors.mockReturnValue(of(2));
363
+
364
+ useCountAncestors(MockEntity as any, { entityId: '1' });
365
+
366
+ expect(MockEntity.countAncestors).toHaveBeenCalledWith({ entityId: '1' });
367
+ });
368
+ });
369
+
370
+ describe('Graph Repository Hooks', () => {
371
+ beforeEach(() => {
372
+ vi.clearAllMocks();
373
+ mockState = [];
374
+ mockStateIndex = 0;
375
+ mockEffectCleanups = [];
376
+ });
377
+
378
+ it('useGraphNeighbors should call findNeighbors', () => {
379
+ MockEntity.findNeighbors.mockReturnValue(of([{ id: '2' }]));
380
+
381
+ useGraphNeighbors(MockEntity as any, { entityId: '1', direction: 'out', level: 1 });
382
+
383
+ expect(MockEntity.findNeighbors).toHaveBeenCalledWith({ entityId: '1', direction: 'out', level: 1 });
384
+ });
385
+
386
+ it('useCountNeighbors should call countNeighbors', () => {
387
+ MockEntity.countNeighbors.mockReturnValue(of(5));
388
+
389
+ useCountNeighbors(MockEntity as any, { entityId: '1', direction: 'out', level: 1 });
390
+
391
+ expect(MockEntity.countNeighbors).toHaveBeenCalledWith({ entityId: '1', direction: 'out', level: 1 });
392
+ });
393
+
394
+ it('useGraphPaths should call findPaths', () => {
395
+ MockEntity.findPaths.mockReturnValue(of([['1', '2', '3']]));
396
+
397
+ useGraphPaths(MockEntity as any, { fromId: '1', toId: '3', maxDepth: 5 });
398
+
399
+ expect(MockEntity.findPaths).toHaveBeenCalledWith({ fromId: '1', toId: '3', maxDepth: 5 });
400
+ });
127
401
  });
@@ -1,7 +1,18 @@
1
1
  import React from 'react';
2
- import { describe, expect, it } from 'vitest';
2
+ import { describe, expect, it, vi } from 'vitest';
3
3
  import { makeRxDBProvider, RxDBProvider, useRxDB } from './rxdb-react';
4
4
 
5
+ // Mock React hooks for testing useRxDB behavior
6
+ let mockContextValue: any = undefined;
7
+ vi.mock('react', async () => {
8
+ const actual = await vi.importActual<typeof React>('react');
9
+ return {
10
+ ...actual,
11
+ useContext: () => mockContextValue,
12
+ createContext: actual.createContext
13
+ };
14
+ });
15
+
5
16
  describe('makeRxDBProvider', () => {
6
17
  it('should create RxDBProvider and useRxDB hook', () => {
7
18
  const { RxDBProvider, useRxDB } = makeRxDBProvider();
@@ -39,3 +50,32 @@ describe('Default exports', () => {
39
50
  expect(typeof makeRxDBProvider).toBe('function');
40
51
  });
41
52
  });
53
+
54
+ describe('useRxDB behavior', () => {
55
+ it('should return provided db parameter if given', () => {
56
+ const { useRxDB } = makeRxDBProvider();
57
+ const directDB = { name: 'direct-db' } as any;
58
+ mockContextValue = { name: 'context-db' };
59
+
60
+ const result = useRxDB(directDB);
61
+
62
+ expect(result).toBe(directDB);
63
+ });
64
+
65
+ it('should return context db when no parameter given', () => {
66
+ const { useRxDB } = makeRxDBProvider();
67
+ const contextDB = { name: 'context-db' };
68
+ mockContextValue = contextDB;
69
+
70
+ const result = useRxDB();
71
+
72
+ expect(result).toBe(contextDB);
73
+ });
74
+
75
+ it('should throw error when no db in context and no parameter', () => {
76
+ const { useRxDB } = makeRxDBProvider();
77
+ mockContextValue = undefined;
78
+
79
+ expect(() => useRxDB()).toThrow('No RxDB instance found, use RxDBProvider to provide one');
80
+ });
81
+ });
package/vite.config.mts CHANGED
@@ -72,9 +72,10 @@ export default defineConfig({
72
72
  coverage: {
73
73
  enabled: true,
74
74
  reportsDirectory: '../../coverage/packages/rxdb-react',
75
- provider: 'v8',
75
+ provider: 'v8' as const,
76
76
  include: ['src/**/*'],
77
- exclude: ['**/index.ts', '**/dist/**']
77
+ exclude: ['**/index.ts', '**/dist/**'],
78
+ all: false
78
79
  }
79
80
  }
80
81
  });