@fluxbase/sdk-react 2026.1.22 → 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.
- package/dist/index.d.mts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +33 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -10
- package/src/context.test.tsx +147 -0
- package/src/index.test.ts +255 -0
- package/src/test-setup.ts +22 -0
- package/src/test-utils.tsx +215 -0
- package/src/use-admin-auth.test.ts +175 -0
- package/src/use-admin-auth.ts +10 -2
- package/src/use-admin-hooks.test.ts +457 -0
- package/src/use-auth-config.test.ts +145 -0
- package/src/use-auth.test.ts +313 -0
- package/src/use-auth.ts +2 -1
- package/src/use-captcha.test.ts +273 -0
- package/src/use-client-keys.test.ts +286 -0
- package/src/use-graphql.test.ts +424 -0
- package/src/use-query.test.ts +348 -0
- package/src/use-query.ts +50 -4
- package/src/use-realtime.test.ts +359 -0
- package/src/use-realtime.ts +20 -15
- package/src/use-saml.test.ts +269 -0
- package/src/use-storage.test.ts +549 -0
- package/src/use-storage.ts +10 -2
- package/src/use-users.test.ts +264 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CAPTCHA hooks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
7
|
+
import { useCaptchaConfig, useCaptcha, isCaptchaRequiredForEndpoint } from './use-captcha';
|
|
8
|
+
import { createMockClient, createWrapper } from './test-utils';
|
|
9
|
+
|
|
10
|
+
describe('useCaptchaConfig', () => {
|
|
11
|
+
it('should fetch CAPTCHA configuration', async () => {
|
|
12
|
+
const mockConfig = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
provider: 'hcaptcha',
|
|
15
|
+
site_key: 'test-site-key',
|
|
16
|
+
endpoints: ['signup', 'login'],
|
|
17
|
+
};
|
|
18
|
+
const getCaptchaConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
19
|
+
|
|
20
|
+
const client = createMockClient({
|
|
21
|
+
auth: { getCaptchaConfig: getCaptchaConfigMock },
|
|
22
|
+
} as any);
|
|
23
|
+
|
|
24
|
+
const { result } = renderHook(
|
|
25
|
+
() => useCaptchaConfig(),
|
|
26
|
+
{ wrapper: createWrapper(client) }
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
30
|
+
expect(result.current.data).toEqual(mockConfig);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should throw error on fetch failure', async () => {
|
|
34
|
+
const error = new Error('Failed to fetch');
|
|
35
|
+
const getCaptchaConfigMock = vi.fn().mockResolvedValue({ data: null, error });
|
|
36
|
+
|
|
37
|
+
const client = createMockClient({
|
|
38
|
+
auth: { getCaptchaConfig: getCaptchaConfigMock },
|
|
39
|
+
} as any);
|
|
40
|
+
|
|
41
|
+
const { result } = renderHook(
|
|
42
|
+
() => useCaptchaConfig(),
|
|
43
|
+
{ wrapper: createWrapper(client) }
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
47
|
+
expect(result.current.error).toBe(error);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('useCaptcha', () => {
|
|
52
|
+
it('should initialize with empty state', () => {
|
|
53
|
+
const client = createMockClient();
|
|
54
|
+
|
|
55
|
+
const { result } = renderHook(
|
|
56
|
+
() => useCaptcha('hcaptcha'),
|
|
57
|
+
{ wrapper: createWrapper(client) }
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(result.current.token).toBeNull();
|
|
61
|
+
expect(result.current.isLoading).toBe(false);
|
|
62
|
+
expect(result.current.error).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should become ready when provider is set', async () => {
|
|
66
|
+
const client = createMockClient();
|
|
67
|
+
|
|
68
|
+
const { result } = renderHook(
|
|
69
|
+
() => useCaptcha('hcaptcha'),
|
|
70
|
+
{ wrapper: createWrapper(client) }
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
await waitFor(() => expect(result.current.isReady).toBe(true));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should handle onVerify callback', () => {
|
|
77
|
+
const client = createMockClient();
|
|
78
|
+
|
|
79
|
+
const { result } = renderHook(
|
|
80
|
+
() => useCaptcha('hcaptcha'),
|
|
81
|
+
{ wrapper: createWrapper(client) }
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
act(() => {
|
|
85
|
+
result.current.onVerify('test-token');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(result.current.token).toBe('test-token');
|
|
89
|
+
expect(result.current.isLoading).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle onExpire callback', () => {
|
|
93
|
+
const client = createMockClient();
|
|
94
|
+
|
|
95
|
+
const { result } = renderHook(
|
|
96
|
+
() => useCaptcha('hcaptcha'),
|
|
97
|
+
{ wrapper: createWrapper(client) }
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// First verify
|
|
101
|
+
act(() => {
|
|
102
|
+
result.current.onVerify('test-token');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(result.current.token).toBe('test-token');
|
|
106
|
+
|
|
107
|
+
// Then expire
|
|
108
|
+
act(() => {
|
|
109
|
+
result.current.onExpire();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(result.current.token).toBeNull();
|
|
113
|
+
expect(result.current.isReady).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should handle onError callback', () => {
|
|
117
|
+
const client = createMockClient();
|
|
118
|
+
|
|
119
|
+
const { result } = renderHook(
|
|
120
|
+
() => useCaptcha('hcaptcha'),
|
|
121
|
+
{ wrapper: createWrapper(client) }
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const error = new Error('CAPTCHA error');
|
|
125
|
+
act(() => {
|
|
126
|
+
result.current.onError(error);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(result.current.error).toBe(error);
|
|
130
|
+
expect(result.current.token).toBeNull();
|
|
131
|
+
expect(result.current.isLoading).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should reset state', () => {
|
|
135
|
+
const client = createMockClient();
|
|
136
|
+
|
|
137
|
+
const { result } = renderHook(
|
|
138
|
+
() => useCaptcha('hcaptcha'),
|
|
139
|
+
{ wrapper: createWrapper(client) }
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Set a token
|
|
143
|
+
act(() => {
|
|
144
|
+
result.current.onVerify('test-token');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(result.current.token).toBe('test-token');
|
|
148
|
+
|
|
149
|
+
// Reset
|
|
150
|
+
act(() => {
|
|
151
|
+
result.current.reset();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
expect(result.current.token).toBeNull();
|
|
155
|
+
expect(result.current.error).toBeNull();
|
|
156
|
+
expect(result.current.isLoading).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should return existing token in execute', async () => {
|
|
160
|
+
const client = createMockClient();
|
|
161
|
+
|
|
162
|
+
const { result } = renderHook(
|
|
163
|
+
() => useCaptcha('hcaptcha'),
|
|
164
|
+
{ wrapper: createWrapper(client) }
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Set a token
|
|
168
|
+
act(() => {
|
|
169
|
+
result.current.onVerify('existing-token');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Execute should return existing token
|
|
173
|
+
let token;
|
|
174
|
+
await act(async () => {
|
|
175
|
+
token = await result.current.execute();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(token).toBe('existing-token');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should return empty string in execute when no provider', async () => {
|
|
182
|
+
const client = createMockClient();
|
|
183
|
+
|
|
184
|
+
const { result } = renderHook(
|
|
185
|
+
() => useCaptcha(undefined),
|
|
186
|
+
{ wrapper: createWrapper(client) }
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
let token;
|
|
190
|
+
await act(async () => {
|
|
191
|
+
token = await result.current.execute();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
expect(token).toBe('');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should set loading state during execute', async () => {
|
|
198
|
+
const client = createMockClient();
|
|
199
|
+
|
|
200
|
+
const { result } = renderHook(
|
|
201
|
+
() => useCaptcha('hcaptcha'),
|
|
202
|
+
{ wrapper: createWrapper(client) }
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// Start execute (returns a promise that needs onVerify to resolve)
|
|
206
|
+
let executePromise: Promise<string>;
|
|
207
|
+
act(() => {
|
|
208
|
+
executePromise = result.current.execute();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(result.current.isLoading).toBe(true);
|
|
212
|
+
|
|
213
|
+
// Resolve by calling onVerify
|
|
214
|
+
act(() => {
|
|
215
|
+
result.current.onVerify('new-token');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const token = await executePromise!;
|
|
219
|
+
expect(token).toBe('new-token');
|
|
220
|
+
expect(result.current.isLoading).toBe(false);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should reject execute on error', async () => {
|
|
224
|
+
const client = createMockClient();
|
|
225
|
+
|
|
226
|
+
const { result } = renderHook(
|
|
227
|
+
() => useCaptcha('hcaptcha'),
|
|
228
|
+
{ wrapper: createWrapper(client) }
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Start execute
|
|
232
|
+
let executePromise: Promise<string>;
|
|
233
|
+
act(() => {
|
|
234
|
+
executePromise = result.current.execute();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Trigger error
|
|
238
|
+
const error = new Error('CAPTCHA failed');
|
|
239
|
+
act(() => {
|
|
240
|
+
result.current.onError(error);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await expect(executePromise!).rejects.toThrow('CAPTCHA failed');
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe('isCaptchaRequiredForEndpoint', () => {
|
|
248
|
+
it('should return false when CAPTCHA is disabled', () => {
|
|
249
|
+
const config = { enabled: false, endpoints: ['signup', 'login'] };
|
|
250
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'signup')).toBe(false);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should return false when config is undefined', () => {
|
|
254
|
+
expect(isCaptchaRequiredForEndpoint(undefined, 'signup')).toBe(false);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should return true when endpoint is in list', () => {
|
|
258
|
+
const config = { enabled: true, endpoints: ['signup', 'login'] };
|
|
259
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'signup')).toBe(true);
|
|
260
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'login')).toBe(true);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should return false when endpoint is not in list', () => {
|
|
264
|
+
const config = { enabled: true, endpoints: ['signup'] };
|
|
265
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'login')).toBe(false);
|
|
266
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'password_reset')).toBe(false);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should return false when endpoints is undefined', () => {
|
|
270
|
+
const config = { enabled: true };
|
|
271
|
+
expect(isCaptchaRequiredForEndpoint(config as any, 'signup')).toBe(false);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for client keys management hook
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
7
|
+
import { useClientKeys, useAPIKeys } from './use-client-keys';
|
|
8
|
+
import { createMockClient, createWrapper } from './test-utils';
|
|
9
|
+
|
|
10
|
+
describe('useClientKeys', () => {
|
|
11
|
+
it('should fetch client keys on mount when autoFetch is true', async () => {
|
|
12
|
+
const mockKeys = [
|
|
13
|
+
{ id: '1', name: 'Key 1', description: 'First key' },
|
|
14
|
+
{ id: '2', name: 'Key 2', description: 'Second key' },
|
|
15
|
+
];
|
|
16
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: mockKeys });
|
|
17
|
+
|
|
18
|
+
const client = createMockClient({
|
|
19
|
+
admin: {
|
|
20
|
+
management: {
|
|
21
|
+
clientKeys: {
|
|
22
|
+
list: listMock,
|
|
23
|
+
create: vi.fn(),
|
|
24
|
+
update: vi.fn(),
|
|
25
|
+
revoke: vi.fn(),
|
|
26
|
+
delete: vi.fn(),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
} as any);
|
|
31
|
+
|
|
32
|
+
const { result } = renderHook(
|
|
33
|
+
() => useClientKeys({ autoFetch: true }),
|
|
34
|
+
{ wrapper: createWrapper(client) }
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
38
|
+
expect(result.current.keys).toEqual(mockKeys);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should not fetch keys when autoFetch is false', async () => {
|
|
42
|
+
const listMock = vi.fn();
|
|
43
|
+
|
|
44
|
+
const client = createMockClient({
|
|
45
|
+
admin: {
|
|
46
|
+
management: {
|
|
47
|
+
clientKeys: {
|
|
48
|
+
list: listMock,
|
|
49
|
+
create: vi.fn(),
|
|
50
|
+
update: vi.fn(),
|
|
51
|
+
revoke: vi.fn(),
|
|
52
|
+
delete: vi.fn(),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
} as any);
|
|
57
|
+
|
|
58
|
+
const { result } = renderHook(
|
|
59
|
+
() => useClientKeys({ autoFetch: false }),
|
|
60
|
+
{ wrapper: createWrapper(client) }
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
64
|
+
expect(listMock).not.toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should create client key', async () => {
|
|
68
|
+
const mockKeys: any[] = [];
|
|
69
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: mockKeys });
|
|
70
|
+
const createMock = vi.fn().mockResolvedValue({
|
|
71
|
+
key: 'new-secret-key',
|
|
72
|
+
client_key: { id: '1', name: 'New Key' },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const client = createMockClient({
|
|
76
|
+
admin: {
|
|
77
|
+
management: {
|
|
78
|
+
clientKeys: {
|
|
79
|
+
list: listMock,
|
|
80
|
+
create: createMock,
|
|
81
|
+
update: vi.fn(),
|
|
82
|
+
revoke: vi.fn(),
|
|
83
|
+
delete: vi.fn(),
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
} as any);
|
|
88
|
+
|
|
89
|
+
const { result } = renderHook(
|
|
90
|
+
() => useClientKeys({ autoFetch: true }),
|
|
91
|
+
{ wrapper: createWrapper(client) }
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
95
|
+
|
|
96
|
+
let response;
|
|
97
|
+
await act(async () => {
|
|
98
|
+
response = await result.current.createKey({
|
|
99
|
+
name: 'New Key',
|
|
100
|
+
description: 'A new key',
|
|
101
|
+
scopes: ['read', 'write'],
|
|
102
|
+
rate_limit_per_minute: 60,
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(createMock).toHaveBeenCalledWith({
|
|
107
|
+
name: 'New Key',
|
|
108
|
+
description: 'A new key',
|
|
109
|
+
scopes: ['read', 'write'],
|
|
110
|
+
rate_limit_per_minute: 60,
|
|
111
|
+
});
|
|
112
|
+
expect(response).toEqual({
|
|
113
|
+
key: 'new-secret-key',
|
|
114
|
+
keyData: { id: '1', name: 'New Key' },
|
|
115
|
+
});
|
|
116
|
+
// Should refetch after create
|
|
117
|
+
expect(listMock).toHaveBeenCalledTimes(2);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should update client key', async () => {
|
|
121
|
+
const mockKeys = [{ id: '1', name: 'Key 1' }];
|
|
122
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: mockKeys });
|
|
123
|
+
const updateMock = vi.fn().mockResolvedValue({});
|
|
124
|
+
|
|
125
|
+
const client = createMockClient({
|
|
126
|
+
admin: {
|
|
127
|
+
management: {
|
|
128
|
+
clientKeys: {
|
|
129
|
+
list: listMock,
|
|
130
|
+
create: vi.fn(),
|
|
131
|
+
update: updateMock,
|
|
132
|
+
revoke: vi.fn(),
|
|
133
|
+
delete: vi.fn(),
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
} as any);
|
|
138
|
+
|
|
139
|
+
const { result } = renderHook(
|
|
140
|
+
() => useClientKeys({ autoFetch: true }),
|
|
141
|
+
{ wrapper: createWrapper(client) }
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
145
|
+
|
|
146
|
+
await act(async () => {
|
|
147
|
+
await result.current.updateKey('1', { name: 'Updated Key' });
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(updateMock).toHaveBeenCalledWith('1', { name: 'Updated Key' });
|
|
151
|
+
// Should refetch after update
|
|
152
|
+
expect(listMock).toHaveBeenCalledTimes(2);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should revoke client key', async () => {
|
|
156
|
+
const mockKeys = [{ id: '1', name: 'Key 1' }];
|
|
157
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: mockKeys });
|
|
158
|
+
const revokeMock = vi.fn().mockResolvedValue({});
|
|
159
|
+
|
|
160
|
+
const client = createMockClient({
|
|
161
|
+
admin: {
|
|
162
|
+
management: {
|
|
163
|
+
clientKeys: {
|
|
164
|
+
list: listMock,
|
|
165
|
+
create: vi.fn(),
|
|
166
|
+
update: vi.fn(),
|
|
167
|
+
revoke: revokeMock,
|
|
168
|
+
delete: vi.fn(),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
} as any);
|
|
173
|
+
|
|
174
|
+
const { result } = renderHook(
|
|
175
|
+
() => useClientKeys({ autoFetch: true }),
|
|
176
|
+
{ wrapper: createWrapper(client) }
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
180
|
+
|
|
181
|
+
await act(async () => {
|
|
182
|
+
await result.current.revokeKey('1');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(revokeMock).toHaveBeenCalledWith('1');
|
|
186
|
+
// Should refetch after revoke
|
|
187
|
+
expect(listMock).toHaveBeenCalledTimes(2);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should delete client key', async () => {
|
|
191
|
+
const mockKeys = [{ id: '1', name: 'Key 1' }];
|
|
192
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: mockKeys });
|
|
193
|
+
const deleteMock = vi.fn().mockResolvedValue({});
|
|
194
|
+
|
|
195
|
+
const client = createMockClient({
|
|
196
|
+
admin: {
|
|
197
|
+
management: {
|
|
198
|
+
clientKeys: {
|
|
199
|
+
list: listMock,
|
|
200
|
+
create: vi.fn(),
|
|
201
|
+
update: vi.fn(),
|
|
202
|
+
revoke: vi.fn(),
|
|
203
|
+
delete: deleteMock,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
} as any);
|
|
208
|
+
|
|
209
|
+
const { result } = renderHook(
|
|
210
|
+
() => useClientKeys({ autoFetch: true }),
|
|
211
|
+
{ wrapper: createWrapper(client) }
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
215
|
+
|
|
216
|
+
await act(async () => {
|
|
217
|
+
await result.current.deleteKey('1');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
expect(deleteMock).toHaveBeenCalledWith('1');
|
|
221
|
+
// Should refetch after delete
|
|
222
|
+
expect(listMock).toHaveBeenCalledTimes(2);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should handle fetch error', async () => {
|
|
226
|
+
const error = new Error('Failed to fetch');
|
|
227
|
+
const listMock = vi.fn().mockRejectedValue(error);
|
|
228
|
+
|
|
229
|
+
const client = createMockClient({
|
|
230
|
+
admin: {
|
|
231
|
+
management: {
|
|
232
|
+
clientKeys: {
|
|
233
|
+
list: listMock,
|
|
234
|
+
create: vi.fn(),
|
|
235
|
+
update: vi.fn(),
|
|
236
|
+
revoke: vi.fn(),
|
|
237
|
+
delete: vi.fn(),
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
} as any);
|
|
242
|
+
|
|
243
|
+
const { result } = renderHook(
|
|
244
|
+
() => useClientKeys({ autoFetch: true }),
|
|
245
|
+
{ wrapper: createWrapper(client) }
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
249
|
+
expect(result.current.error).toBe(error);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should refetch on demand', async () => {
|
|
253
|
+
const listMock = vi.fn().mockResolvedValue({ client_keys: [] });
|
|
254
|
+
|
|
255
|
+
const client = createMockClient({
|
|
256
|
+
admin: {
|
|
257
|
+
management: {
|
|
258
|
+
clientKeys: {
|
|
259
|
+
list: listMock,
|
|
260
|
+
create: vi.fn(),
|
|
261
|
+
update: vi.fn(),
|
|
262
|
+
revoke: vi.fn(),
|
|
263
|
+
delete: vi.fn(),
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
} as any);
|
|
268
|
+
|
|
269
|
+
const { result } = renderHook(
|
|
270
|
+
() => useClientKeys({ autoFetch: false }),
|
|
271
|
+
{ wrapper: createWrapper(client) }
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
await act(async () => {
|
|
275
|
+
await result.current.refetch();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
expect(listMock).toHaveBeenCalledTimes(1);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe('useAPIKeys (deprecated alias)', () => {
|
|
283
|
+
it('should be the same as useClientKeys', () => {
|
|
284
|
+
expect(useAPIKeys).toBe(useClientKeys);
|
|
285
|
+
});
|
|
286
|
+
});
|