@fluxbase/sdk-react 2026.1.22-rc.9 → 2026.2.1

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.
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Tests for users management hook
3
+ */
4
+
5
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
6
+ import { renderHook, waitFor, act } from '@testing-library/react';
7
+ import { useUsers } from './use-users';
8
+ import { createMockClient, createWrapper } from './test-utils';
9
+
10
+ describe('useUsers', () => {
11
+ it('should fetch users on mount when autoFetch is true', async () => {
12
+ const mockUsers = [
13
+ { id: '1', email: 'user1@example.com', role: 'user' },
14
+ { id: '2', email: 'user2@example.com', role: 'admin' },
15
+ ];
16
+ const listUsersMock = vi.fn().mockResolvedValue({
17
+ data: { users: mockUsers, total: 2 },
18
+ error: null,
19
+ });
20
+
21
+ const client = createMockClient({
22
+ admin: { listUsers: listUsersMock },
23
+ } as any);
24
+
25
+ const { result } = renderHook(
26
+ () => useUsers({ autoFetch: true }),
27
+ { wrapper: createWrapper(client) }
28
+ );
29
+
30
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
31
+ expect(result.current.users).toEqual(mockUsers);
32
+ expect(result.current.total).toBe(2);
33
+ });
34
+
35
+ it('should not fetch users when autoFetch is false', async () => {
36
+ const listUsersMock = vi.fn();
37
+
38
+ const client = createMockClient({
39
+ admin: { listUsers: listUsersMock },
40
+ } as any);
41
+
42
+ const { result } = renderHook(
43
+ () => useUsers({ autoFetch: false }),
44
+ { wrapper: createWrapper(client) }
45
+ );
46
+
47
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
48
+ expect(listUsersMock).not.toHaveBeenCalled();
49
+ });
50
+
51
+ it('should pass list options', async () => {
52
+ const listUsersMock = vi.fn().mockResolvedValue({
53
+ data: { users: [], total: 0 },
54
+ error: null,
55
+ });
56
+
57
+ const client = createMockClient({
58
+ admin: { listUsers: listUsersMock },
59
+ } as any);
60
+
61
+ renderHook(
62
+ () => useUsers({ autoFetch: true, limit: 10, search: 'test' }),
63
+ { wrapper: createWrapper(client) }
64
+ );
65
+
66
+ await waitFor(() => {
67
+ expect(listUsersMock).toHaveBeenCalledWith(
68
+ expect.objectContaining({ limit: 10, search: 'test' })
69
+ );
70
+ });
71
+ });
72
+
73
+ it('should invite user', async () => {
74
+ const listUsersMock = vi.fn().mockResolvedValue({
75
+ data: { users: [], total: 0 },
76
+ error: null,
77
+ });
78
+ const inviteUserMock = vi.fn().mockResolvedValue({ data: {}, error: null });
79
+
80
+ const client = createMockClient({
81
+ admin: {
82
+ listUsers: listUsersMock,
83
+ inviteUser: inviteUserMock,
84
+ },
85
+ } as any);
86
+
87
+ const { result } = renderHook(
88
+ () => useUsers({ autoFetch: true }),
89
+ { wrapper: createWrapper(client) }
90
+ );
91
+
92
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
93
+
94
+ await act(async () => {
95
+ await result.current.inviteUser('new@example.com', 'user');
96
+ });
97
+
98
+ expect(inviteUserMock).toHaveBeenCalledWith({ email: 'new@example.com', role: 'user' });
99
+ // Should refetch after invite
100
+ expect(listUsersMock).toHaveBeenCalledTimes(2);
101
+ });
102
+
103
+ it('should update user role', async () => {
104
+ const listUsersMock = vi.fn().mockResolvedValue({
105
+ data: { users: [], total: 0 },
106
+ error: null,
107
+ });
108
+ const updateUserRoleMock = vi.fn().mockResolvedValue({ data: {}, error: null });
109
+
110
+ const client = createMockClient({
111
+ admin: {
112
+ listUsers: listUsersMock,
113
+ updateUserRole: updateUserRoleMock,
114
+ },
115
+ } as any);
116
+
117
+ const { result } = renderHook(
118
+ () => useUsers({ autoFetch: true }),
119
+ { wrapper: createWrapper(client) }
120
+ );
121
+
122
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
123
+
124
+ await act(async () => {
125
+ await result.current.updateUserRole('1', 'admin');
126
+ });
127
+
128
+ expect(updateUserRoleMock).toHaveBeenCalledWith('1', 'admin');
129
+ // Should refetch after update
130
+ expect(listUsersMock).toHaveBeenCalledTimes(2);
131
+ });
132
+
133
+ it('should delete user', async () => {
134
+ const listUsersMock = vi.fn().mockResolvedValue({
135
+ data: { users: [], total: 0 },
136
+ error: null,
137
+ });
138
+ const deleteUserMock = vi.fn().mockResolvedValue({ data: {}, error: null });
139
+
140
+ const client = createMockClient({
141
+ admin: {
142
+ listUsers: listUsersMock,
143
+ deleteUser: deleteUserMock,
144
+ },
145
+ } as any);
146
+
147
+ const { result } = renderHook(
148
+ () => useUsers({ autoFetch: true }),
149
+ { wrapper: createWrapper(client) }
150
+ );
151
+
152
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
153
+
154
+ await act(async () => {
155
+ await result.current.deleteUser('1');
156
+ });
157
+
158
+ expect(deleteUserMock).toHaveBeenCalledWith('1');
159
+ // Should refetch after delete
160
+ expect(listUsersMock).toHaveBeenCalledTimes(2);
161
+ });
162
+
163
+ it('should reset user password', async () => {
164
+ const listUsersMock = vi.fn().mockResolvedValue({
165
+ data: { users: [], total: 0 },
166
+ error: null,
167
+ });
168
+ const resetPasswordMock = vi.fn().mockResolvedValue({
169
+ data: { message: 'Password reset email sent' },
170
+ error: null,
171
+ });
172
+
173
+ const client = createMockClient({
174
+ admin: {
175
+ listUsers: listUsersMock,
176
+ resetUserPassword: resetPasswordMock,
177
+ },
178
+ } as any);
179
+
180
+ const { result } = renderHook(
181
+ () => useUsers({ autoFetch: true }),
182
+ { wrapper: createWrapper(client) }
183
+ );
184
+
185
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
186
+
187
+ let response;
188
+ await act(async () => {
189
+ response = await result.current.resetPassword('1');
190
+ });
191
+
192
+ expect(resetPasswordMock).toHaveBeenCalledWith('1');
193
+ expect(response).toEqual({ message: 'Password reset email sent' });
194
+ });
195
+
196
+ it('should handle fetch error', async () => {
197
+ const error = new Error('Failed to fetch');
198
+ const listUsersMock = vi.fn().mockResolvedValue({ data: null, error });
199
+
200
+ const client = createMockClient({
201
+ admin: { listUsers: listUsersMock },
202
+ } as any);
203
+
204
+ const { result } = renderHook(
205
+ () => useUsers({ autoFetch: true }),
206
+ { wrapper: createWrapper(client) }
207
+ );
208
+
209
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
210
+ expect(result.current.error).toBe(error);
211
+ });
212
+
213
+ it('should set up refetch interval', async () => {
214
+ vi.useFakeTimers();
215
+ const listUsersMock = vi.fn().mockResolvedValue({
216
+ data: { users: [], total: 0 },
217
+ error: null,
218
+ });
219
+
220
+ const client = createMockClient({
221
+ admin: { listUsers: listUsersMock },
222
+ } as any);
223
+
224
+ const { unmount } = renderHook(
225
+ () => useUsers({ autoFetch: true, refetchInterval: 5000 }),
226
+ { wrapper: createWrapper(client) }
227
+ );
228
+
229
+ // Initial fetch
230
+ expect(listUsersMock).toHaveBeenCalledTimes(1);
231
+
232
+ // Advance timer
233
+ await act(async () => {
234
+ vi.advanceTimersByTime(5000);
235
+ });
236
+
237
+ expect(listUsersMock).toHaveBeenCalledTimes(2);
238
+
239
+ unmount();
240
+ vi.useRealTimers();
241
+ });
242
+
243
+ it('should refetch on demand', async () => {
244
+ const listUsersMock = vi.fn().mockResolvedValue({
245
+ data: { users: [], total: 0 },
246
+ error: null,
247
+ });
248
+
249
+ const client = createMockClient({
250
+ admin: { listUsers: listUsersMock },
251
+ } as any);
252
+
253
+ const { result } = renderHook(
254
+ () => useUsers({ autoFetch: false }),
255
+ { wrapper: createWrapper(client) }
256
+ );
257
+
258
+ await act(async () => {
259
+ await result.current.refetch();
260
+ });
261
+
262
+ expect(listUsersMock).toHaveBeenCalledTimes(1);
263
+ });
264
+ });
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: 'jsdom',
6
+ globals: true,
7
+ setupFiles: ['./src/test-setup.ts'],
8
+ coverage: {
9
+ provider: 'v8',
10
+ reporter: ['text', 'json', 'html', 'lcov'],
11
+ reportsDirectory: './coverage',
12
+ include: ['src/**/*.ts', 'src/**/*.tsx'],
13
+ exclude: ['src/**/*.test.ts', 'src/**/*.test.tsx', 'src/**/*.d.ts', 'src/test-setup.ts'],
14
+ thresholds: {
15
+ statements: 80,
16
+ branches: 80,
17
+ functions: 60,
18
+ lines: 80
19
+ }
20
+ }
21
+ }
22
+ });