@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.
- 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,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for auth configuration hook
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
+
import { renderHook, waitFor } from '@testing-library/react';
|
|
7
|
+
import { useAuthConfig } from './use-auth-config';
|
|
8
|
+
import { createMockClient, createWrapper } from './test-utils';
|
|
9
|
+
|
|
10
|
+
describe('useAuthConfig', () => {
|
|
11
|
+
it('should fetch auth configuration', async () => {
|
|
12
|
+
const mockConfig = {
|
|
13
|
+
signup_enabled: true,
|
|
14
|
+
email_verification_required: true,
|
|
15
|
+
magic_link_enabled: true,
|
|
16
|
+
mfa_enabled: true,
|
|
17
|
+
password_min_length: 8,
|
|
18
|
+
password_require_uppercase: true,
|
|
19
|
+
password_require_lowercase: true,
|
|
20
|
+
password_require_number: true,
|
|
21
|
+
password_require_special: false,
|
|
22
|
+
oauth_providers: [
|
|
23
|
+
{ provider: 'google', display_name: 'Google', authorize_url: 'https://google.com/oauth' },
|
|
24
|
+
],
|
|
25
|
+
saml_providers: [],
|
|
26
|
+
captcha: { enabled: false },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
30
|
+
|
|
31
|
+
const client = createMockClient({
|
|
32
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
33
|
+
} as any);
|
|
34
|
+
|
|
35
|
+
const { result } = renderHook(
|
|
36
|
+
() => useAuthConfig(),
|
|
37
|
+
{ wrapper: createWrapper(client) }
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
41
|
+
expect(result.current.data).toEqual(mockConfig);
|
|
42
|
+
expect(getAuthConfigMock).toHaveBeenCalled();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should throw error on fetch failure', async () => {
|
|
46
|
+
const error = new Error('Failed to fetch config');
|
|
47
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: null, error });
|
|
48
|
+
|
|
49
|
+
const client = createMockClient({
|
|
50
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
51
|
+
} as any);
|
|
52
|
+
|
|
53
|
+
const { result } = renderHook(
|
|
54
|
+
() => useAuthConfig(),
|
|
55
|
+
{ wrapper: createWrapper(client) }
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
await waitFor(() => expect(result.current.isError).toBe(true));
|
|
59
|
+
expect(result.current.error).toBe(error);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should have appropriate stale time', async () => {
|
|
63
|
+
const mockConfig = { signup_enabled: true };
|
|
64
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
65
|
+
|
|
66
|
+
const client = createMockClient({
|
|
67
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
68
|
+
} as any);
|
|
69
|
+
|
|
70
|
+
const { result } = renderHook(
|
|
71
|
+
() => useAuthConfig(),
|
|
72
|
+
{ wrapper: createWrapper(client) }
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
76
|
+
|
|
77
|
+
// The config should be cached with a stale time of 5 minutes
|
|
78
|
+
// Verify the data is available
|
|
79
|
+
expect(result.current.data).toEqual(mockConfig);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should return signup enabled status', async () => {
|
|
83
|
+
const mockConfig = { signup_enabled: false };
|
|
84
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
85
|
+
|
|
86
|
+
const client = createMockClient({
|
|
87
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
88
|
+
} as any);
|
|
89
|
+
|
|
90
|
+
const { result } = renderHook(
|
|
91
|
+
() => useAuthConfig(),
|
|
92
|
+
{ wrapper: createWrapper(client) }
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
96
|
+
expect(result.current.data?.signup_enabled).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should return OAuth providers', async () => {
|
|
100
|
+
const mockConfig = {
|
|
101
|
+
oauth_providers: [
|
|
102
|
+
{ provider: 'google', display_name: 'Google', authorize_url: 'https://google.com' },
|
|
103
|
+
{ provider: 'github', display_name: 'GitHub', authorize_url: 'https://github.com' },
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
107
|
+
|
|
108
|
+
const client = createMockClient({
|
|
109
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
110
|
+
} as any);
|
|
111
|
+
|
|
112
|
+
const { result } = renderHook(
|
|
113
|
+
() => useAuthConfig(),
|
|
114
|
+
{ wrapper: createWrapper(client) }
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
118
|
+
expect(result.current.data?.oauth_providers).toHaveLength(2);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return password requirements', async () => {
|
|
122
|
+
const mockConfig = {
|
|
123
|
+
password_min_length: 12,
|
|
124
|
+
password_require_uppercase: true,
|
|
125
|
+
password_require_lowercase: true,
|
|
126
|
+
password_require_number: true,
|
|
127
|
+
password_require_special: true,
|
|
128
|
+
};
|
|
129
|
+
const getAuthConfigMock = vi.fn().mockResolvedValue({ data: mockConfig, error: null });
|
|
130
|
+
|
|
131
|
+
const client = createMockClient({
|
|
132
|
+
auth: { getAuthConfig: getAuthConfigMock },
|
|
133
|
+
} as any);
|
|
134
|
+
|
|
135
|
+
const { result } = renderHook(
|
|
136
|
+
() => useAuthConfig(),
|
|
137
|
+
{ wrapper: createWrapper(client) }
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
141
|
+
expect(result.current.data?.password_min_length).toBe(12);
|
|
142
|
+
expect(result.current.data?.password_require_uppercase).toBe(true);
|
|
143
|
+
expect(result.current.data?.password_require_special).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for authentication hooks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
7
|
+
import {
|
|
8
|
+
useUser,
|
|
9
|
+
useSession,
|
|
10
|
+
useSignIn,
|
|
11
|
+
useSignUp,
|
|
12
|
+
useSignOut,
|
|
13
|
+
useUpdateUser,
|
|
14
|
+
useAuth,
|
|
15
|
+
} from './use-auth';
|
|
16
|
+
import { createMockClient, createWrapper, createTestQueryClient } from './test-utils';
|
|
17
|
+
|
|
18
|
+
describe('useUser', () => {
|
|
19
|
+
it('should return null when no session', async () => {
|
|
20
|
+
const client = createMockClient({
|
|
21
|
+
auth: {
|
|
22
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
23
|
+
},
|
|
24
|
+
} as any);
|
|
25
|
+
|
|
26
|
+
const { result } = renderHook(() => useUser(), {
|
|
27
|
+
wrapper: createWrapper(client),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
31
|
+
expect(result.current.data).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return user when session exists', async () => {
|
|
35
|
+
const mockUser = { id: '1', email: 'test@example.com' };
|
|
36
|
+
const client = createMockClient({
|
|
37
|
+
auth: {
|
|
38
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: { access_token: 'token' } }, error: null }),
|
|
39
|
+
getCurrentUser: vi.fn().mockResolvedValue({ data: { user: mockUser }, error: null }),
|
|
40
|
+
},
|
|
41
|
+
} as any);
|
|
42
|
+
|
|
43
|
+
const { result } = renderHook(() => useUser(), {
|
|
44
|
+
wrapper: createWrapper(client),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
48
|
+
expect(result.current.data).toEqual(mockUser);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return null when getCurrentUser fails', async () => {
|
|
52
|
+
const client = createMockClient({
|
|
53
|
+
auth: {
|
|
54
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: { access_token: 'token' } }, error: null }),
|
|
55
|
+
getCurrentUser: vi.fn().mockRejectedValue(new Error('Not authenticated')),
|
|
56
|
+
},
|
|
57
|
+
} as any);
|
|
58
|
+
|
|
59
|
+
const { result } = renderHook(() => useUser(), {
|
|
60
|
+
wrapper: createWrapper(client),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
64
|
+
expect(result.current.data).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('useSession', () => {
|
|
69
|
+
it('should return null when no session', async () => {
|
|
70
|
+
const client = createMockClient({
|
|
71
|
+
auth: {
|
|
72
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
73
|
+
},
|
|
74
|
+
} as any);
|
|
75
|
+
|
|
76
|
+
const { result } = renderHook(() => useSession(), {
|
|
77
|
+
wrapper: createWrapper(client),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
81
|
+
expect(result.current.data).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return session when exists', async () => {
|
|
85
|
+
const mockSession = { access_token: 'token', refresh_token: 'refresh' };
|
|
86
|
+
const client = createMockClient({
|
|
87
|
+
auth: {
|
|
88
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: mockSession }, error: null }),
|
|
89
|
+
},
|
|
90
|
+
} as any);
|
|
91
|
+
|
|
92
|
+
const { result } = renderHook(() => useSession(), {
|
|
93
|
+
wrapper: createWrapper(client),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
97
|
+
expect(result.current.data).toEqual(mockSession);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('useSignIn', () => {
|
|
102
|
+
it('should call signIn and update cache on success', async () => {
|
|
103
|
+
const mockSession = { user: { id: '1', email: 'test@example.com' }, access_token: 'token' };
|
|
104
|
+
const signInMock = vi.fn().mockResolvedValue(mockSession);
|
|
105
|
+
const client = createMockClient({
|
|
106
|
+
auth: {
|
|
107
|
+
signIn: signInMock,
|
|
108
|
+
},
|
|
109
|
+
} as any);
|
|
110
|
+
|
|
111
|
+
const queryClient = createTestQueryClient();
|
|
112
|
+
const { result } = renderHook(() => useSignIn(), {
|
|
113
|
+
wrapper: createWrapper(client, queryClient),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await act(async () => {
|
|
117
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(signInMock).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password' });
|
|
121
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'session'])).toEqual(mockSession);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should handle 2FA required response (no user)', async () => {
|
|
125
|
+
const mockResponse = { mfa_required: true };
|
|
126
|
+
const signInMock = vi.fn().mockResolvedValue(mockResponse);
|
|
127
|
+
const client = createMockClient({
|
|
128
|
+
auth: {
|
|
129
|
+
signIn: signInMock,
|
|
130
|
+
},
|
|
131
|
+
} as any);
|
|
132
|
+
|
|
133
|
+
const queryClient = createTestQueryClient();
|
|
134
|
+
const { result } = renderHook(() => useSignIn(), {
|
|
135
|
+
wrapper: createWrapper(client, queryClient),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await act(async () => {
|
|
139
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// User should not be set when 2FA is required
|
|
143
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'user'])).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('useSignUp', () => {
|
|
148
|
+
it('should call signUp and return response on success', async () => {
|
|
149
|
+
const mockResponse = {
|
|
150
|
+
data: {
|
|
151
|
+
user: { id: '1', email: 'test@example.com' },
|
|
152
|
+
session: { access_token: 'token' },
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
const signUpMock = vi.fn().mockResolvedValue(mockResponse);
|
|
156
|
+
const client = createMockClient({
|
|
157
|
+
auth: {
|
|
158
|
+
signUp: signUpMock,
|
|
159
|
+
},
|
|
160
|
+
} as any);
|
|
161
|
+
|
|
162
|
+
const { result } = renderHook(() => useSignUp(), {
|
|
163
|
+
wrapper: createWrapper(client),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
let response;
|
|
167
|
+
await act(async () => {
|
|
168
|
+
response = await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(signUpMock).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password' });
|
|
172
|
+
expect(response).toEqual(mockResponse);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle signup without immediate session', async () => {
|
|
176
|
+
const mockResponse = { data: null };
|
|
177
|
+
const signUpMock = vi.fn().mockResolvedValue(mockResponse);
|
|
178
|
+
const client = createMockClient({
|
|
179
|
+
auth: {
|
|
180
|
+
signUp: signUpMock,
|
|
181
|
+
},
|
|
182
|
+
} as any);
|
|
183
|
+
|
|
184
|
+
const queryClient = createTestQueryClient();
|
|
185
|
+
const { result } = renderHook(() => useSignUp(), {
|
|
186
|
+
wrapper: createWrapper(client, queryClient),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
await act(async () => {
|
|
190
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Cache should not be updated when data is null
|
|
194
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'session'])).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('useSignOut', () => {
|
|
199
|
+
it('should call signOut successfully', async () => {
|
|
200
|
+
const signOutMock = vi.fn().mockResolvedValue(undefined);
|
|
201
|
+
const client = createMockClient({
|
|
202
|
+
auth: {
|
|
203
|
+
signOut: signOutMock,
|
|
204
|
+
},
|
|
205
|
+
} as any);
|
|
206
|
+
|
|
207
|
+
const { result } = renderHook(() => useSignOut(), {
|
|
208
|
+
wrapper: createWrapper(client),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
await act(async () => {
|
|
212
|
+
await result.current.mutateAsync();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(signOutMock).toHaveBeenCalled();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('useUpdateUser', () => {
|
|
220
|
+
it('should call updateUser and update cache', async () => {
|
|
221
|
+
const updatedUser = { id: '1', email: 'new@example.com' };
|
|
222
|
+
const updateUserMock = vi.fn().mockResolvedValue(updatedUser);
|
|
223
|
+
const client = createMockClient({
|
|
224
|
+
auth: {
|
|
225
|
+
updateUser: updateUserMock,
|
|
226
|
+
},
|
|
227
|
+
} as any);
|
|
228
|
+
|
|
229
|
+
const queryClient = createTestQueryClient();
|
|
230
|
+
const { result } = renderHook(() => useUpdateUser(), {
|
|
231
|
+
wrapper: createWrapper(client, queryClient),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await act(async () => {
|
|
235
|
+
await result.current.mutateAsync({ email: 'new@example.com' });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
expect(updateUserMock).toHaveBeenCalledWith({ email: 'new@example.com' });
|
|
239
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'user'])).toEqual(updatedUser);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('useAuth', () => {
|
|
244
|
+
it('should return combined auth state', async () => {
|
|
245
|
+
const mockUser = { id: '1', email: 'test@example.com' };
|
|
246
|
+
const mockSession = { access_token: 'token' };
|
|
247
|
+
const client = createMockClient({
|
|
248
|
+
auth: {
|
|
249
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: mockSession }, error: null }),
|
|
250
|
+
getCurrentUser: vi.fn().mockResolvedValue({ data: { user: mockUser }, error: null }),
|
|
251
|
+
},
|
|
252
|
+
} as any);
|
|
253
|
+
|
|
254
|
+
const { result } = renderHook(() => useAuth(), {
|
|
255
|
+
wrapper: createWrapper(client),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
259
|
+
|
|
260
|
+
expect(result.current.user).toEqual(mockUser);
|
|
261
|
+
expect(result.current.session).toEqual(mockSession);
|
|
262
|
+
expect(result.current.isAuthenticated).toBe(true);
|
|
263
|
+
expect(result.current.signIn).toBeDefined();
|
|
264
|
+
expect(result.current.signUp).toBeDefined();
|
|
265
|
+
expect(result.current.signOut).toBeDefined();
|
|
266
|
+
expect(result.current.updateUser).toBeDefined();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should show loading state initially', () => {
|
|
270
|
+
const client = createMockClient({
|
|
271
|
+
auth: {
|
|
272
|
+
getSession: vi.fn().mockImplementation(() => new Promise(() => {})), // Never resolves
|
|
273
|
+
},
|
|
274
|
+
} as any);
|
|
275
|
+
|
|
276
|
+
const { result } = renderHook(() => useAuth(), {
|
|
277
|
+
wrapper: createWrapper(client),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(result.current.isLoading).toBe(true);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should show unauthenticated state when no session', async () => {
|
|
284
|
+
const client = createMockClient({
|
|
285
|
+
auth: {
|
|
286
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
287
|
+
},
|
|
288
|
+
} as any);
|
|
289
|
+
|
|
290
|
+
const { result } = renderHook(() => useAuth(), {
|
|
291
|
+
wrapper: createWrapper(client),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
295
|
+
|
|
296
|
+
expect(result.current.user).toBeNull();
|
|
297
|
+
expect(result.current.session).toBeNull();
|
|
298
|
+
expect(result.current.isAuthenticated).toBe(false);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should have pending states for mutations', () => {
|
|
302
|
+
const client = createMockClient();
|
|
303
|
+
|
|
304
|
+
const { result } = renderHook(() => useAuth(), {
|
|
305
|
+
wrapper: createWrapper(client),
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(result.current.isSigningIn).toBe(false);
|
|
309
|
+
expect(result.current.isSigningUp).toBe(false);
|
|
310
|
+
expect(result.current.isSigningOut).toBe(false);
|
|
311
|
+
expect(result.current.isUpdating).toBe(false);
|
|
312
|
+
});
|
|
313
|
+
});
|
package/src/use-auth.ts
CHANGED
|
@@ -66,7 +66,8 @@ export function useSignIn() {
|
|
|
66
66
|
onSuccess: (session) => {
|
|
67
67
|
queryClient.setQueryData(["fluxbase", "auth", "session"], session);
|
|
68
68
|
// Only set user if this is a complete auth session (not 2FA required)
|
|
69
|
-
|
|
69
|
+
// Check for truthy user value, not just property existence
|
|
70
|
+
if (session && "user" in session && session.user) {
|
|
70
71
|
queryClient.setQueryData(["fluxbase", "auth", "user"], session.user);
|
|
71
72
|
}
|
|
72
73
|
},
|