create-nuxt-base 1.2.0 → 2.1.0
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/CHANGELOG.md +40 -0
- package/nuxt-base-template/.github/workflows/test.yml +90 -0
- package/nuxt-base-template/app/components/Modal/ModalBackupCodes.vue +2 -1
- package/nuxt-base-template/app/components/Upload/TusFileUpload.vue +7 -7
- package/nuxt-base-template/app/interfaces/user.interface.ts +5 -12
- package/nuxt-base-template/app/layouts/default.vue +1 -1
- package/nuxt-base-template/app/middleware/admin.global.ts +2 -2
- package/nuxt-base-template/app/middleware/auth.global.ts +2 -2
- package/nuxt-base-template/app/middleware/guest.global.ts +2 -2
- package/nuxt-base-template/app/pages/app/index.vue +1 -1
- package/nuxt-base-template/app/pages/app/settings/security.vue +54 -43
- package/nuxt-base-template/app/pages/auth/2fa.vue +2 -3
- package/nuxt-base-template/app/pages/auth/forgot-password.vue +2 -1
- package/nuxt-base-template/app/pages/auth/login.vue +6 -4
- package/nuxt-base-template/app/pages/auth/register.vue +85 -61
- package/nuxt-base-template/app/pages/auth/reset-password.vue +2 -1
- package/nuxt-base-template/docs/pages/docs.vue +1 -1
- package/nuxt-base-template/nuxt.config.ts +50 -1
- package/nuxt-base-template/package-lock.json +1311 -2920
- package/nuxt-base-template/package.json +27 -2
- package/nuxt-base-template/playwright.config.ts +1 -1
- package/nuxt-base-template/tests/e2e/auth.spec.ts +467 -0
- package/nuxt-base-template/tests/unit/auth/auth.spec.ts +439 -0
- package/nuxt-base-template/tests/unit/auth/error-translation.spec.ts +279 -0
- package/nuxt-base-template/tests/unit/mocks/auth-client.mock.ts +165 -0
- package/nuxt-base-template/tests/unit/mocks/nuxt-imports.ts +105 -0
- package/nuxt-base-template/tests/unit/setup.ts +56 -0
- package/nuxt-base-template/vitest.config.ts +25 -0
- package/package.json +1 -1
- package/nuxt-base-template/app/components/Transition/TransitionFade.vue +0 -27
- package/nuxt-base-template/app/components/Transition/TransitionFadeScale.vue +0 -27
- package/nuxt-base-template/app/components/Transition/TransitionSlide.vue +0 -12
- package/nuxt-base-template/app/components/Transition/TransitionSlideBottom.vue +0 -12
- package/nuxt-base-template/app/components/Transition/TransitionSlideRevert.vue +0 -12
- package/nuxt-base-template/app/composables/use-better-auth.ts +0 -597
- package/nuxt-base-template/app/composables/use-file.ts +0 -71
- package/nuxt-base-template/app/composables/use-share.ts +0 -38
- package/nuxt-base-template/app/composables/use-tus-upload.ts +0 -278
- package/nuxt-base-template/app/composables/use-tw.ts +0 -1
- package/nuxt-base-template/app/interfaces/upload.interface.ts +0 -58
- package/nuxt-base-template/app/lib/auth-client.ts +0 -229
- package/nuxt-base-template/app/lib/auth-state.ts +0 -206
- package/nuxt-base-template/app/plugins/auth-interceptor.client.ts +0 -151
- package/nuxt-base-template/app/utils/crypto.ts +0 -44
- package/nuxt-base-template/tests/iam.spec.ts +0 -247
- /package/nuxt-base-template/tests/{init.spec.ts → e2e/init.spec.ts} +0 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication Unit Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests cover the same functionality as the E2E Playwright tests,
|
|
5
|
+
* but use mocks instead of real servers. They can run in CI/CD pipelines.
|
|
6
|
+
*
|
|
7
|
+
* Test Coverage:
|
|
8
|
+
* - User registration
|
|
9
|
+
* - Login with email/password
|
|
10
|
+
* - Logout
|
|
11
|
+
* - 2FA enable/disable/verify
|
|
12
|
+
* - Passkey management
|
|
13
|
+
* - Error translations
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
17
|
+
import {
|
|
18
|
+
createMockAuthClient,
|
|
19
|
+
mockUser,
|
|
20
|
+
mockTotpData,
|
|
21
|
+
mockPasskey,
|
|
22
|
+
resetMockAuthClient,
|
|
23
|
+
} from '../mocks/auth-client.mock';
|
|
24
|
+
import { resetCookies } from '../setup';
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Test Suite: Registration
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
describe('Registration', () => {
|
|
31
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
authClient = createMockAuthClient();
|
|
35
|
+
resetCookies();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should register a new user with valid credentials', async () => {
|
|
39
|
+
const newUser = {
|
|
40
|
+
email: 'new@test.com',
|
|
41
|
+
password: 'SecurePass123!',
|
|
42
|
+
name: 'New User',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const result = await authClient.signUp.email(newUser);
|
|
46
|
+
|
|
47
|
+
expect(result.error).toBeNull();
|
|
48
|
+
expect(result.data).not.toBeNull();
|
|
49
|
+
expect(result.data?.user.email).toBe(newUser.email);
|
|
50
|
+
expect(result.data?.user.name).toBe(newUser.name);
|
|
51
|
+
expect(authClient.signUp.email).toHaveBeenCalledWith(newUser);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should have a session after registration', async () => {
|
|
55
|
+
await authClient.signUp.email({
|
|
56
|
+
email: 'new@test.com',
|
|
57
|
+
password: 'SecurePass123!',
|
|
58
|
+
name: 'New User',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const session = authClient._getSession();
|
|
62
|
+
expect(session).not.toBeNull();
|
|
63
|
+
expect(session?.user.email).toBe('new@test.com');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// Test Suite: Login
|
|
69
|
+
// ============================================================================
|
|
70
|
+
|
|
71
|
+
describe('Login', () => {
|
|
72
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
authClient = createMockAuthClient();
|
|
76
|
+
resetCookies();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should login with valid email and password', async () => {
|
|
80
|
+
const credentials = {
|
|
81
|
+
email: 'test@example.com',
|
|
82
|
+
password: 'SecurePass123!',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const result = await authClient.signIn.email(credentials);
|
|
86
|
+
|
|
87
|
+
expect(result.error).toBeNull();
|
|
88
|
+
expect(result.data).not.toBeNull();
|
|
89
|
+
expect(result.data?.user.email).toBe(credentials.email);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should fail login with invalid credentials', async () => {
|
|
93
|
+
const credentials = {
|
|
94
|
+
email: 'invalid@test.com',
|
|
95
|
+
password: 'WrongPassword!',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const result = await authClient.signIn.email(credentials);
|
|
99
|
+
|
|
100
|
+
expect(result.error).not.toBeNull();
|
|
101
|
+
expect(result.error?.message).toBe('Ungültige Anmeldedaten');
|
|
102
|
+
expect(result.data).toBeNull();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should login with passkey', async () => {
|
|
106
|
+
const result = await authClient.signIn.passkey();
|
|
107
|
+
|
|
108
|
+
expect(result.error).toBeNull();
|
|
109
|
+
expect(result.data).not.toBeNull();
|
|
110
|
+
expect(result.data?.user).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Test Suite: Logout
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
describe('Logout', () => {
|
|
119
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
120
|
+
|
|
121
|
+
beforeEach(async () => {
|
|
122
|
+
authClient = createMockAuthClient();
|
|
123
|
+
resetCookies();
|
|
124
|
+
// Login first
|
|
125
|
+
await authClient.signIn.email({
|
|
126
|
+
email: 'test@example.com',
|
|
127
|
+
password: 'SecurePass123!',
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should have session before logout', () => {
|
|
132
|
+
const session = authClient._getSession();
|
|
133
|
+
expect(session).not.toBeNull();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should clear session after logout', async () => {
|
|
137
|
+
await authClient.signOut();
|
|
138
|
+
|
|
139
|
+
const session = authClient._getSession();
|
|
140
|
+
expect(session).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should call signOut method', async () => {
|
|
144
|
+
await authClient.signOut();
|
|
145
|
+
expect(authClient.signOut).toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Test Suite: Two-Factor Authentication (2FA)
|
|
151
|
+
// ============================================================================
|
|
152
|
+
|
|
153
|
+
describe('Two-Factor Authentication', () => {
|
|
154
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
155
|
+
|
|
156
|
+
beforeEach(async () => {
|
|
157
|
+
authClient = createMockAuthClient();
|
|
158
|
+
resetCookies();
|
|
159
|
+
// Login first
|
|
160
|
+
await authClient.signIn.email({
|
|
161
|
+
email: 'test@example.com',
|
|
162
|
+
password: 'SecurePass123!',
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Enable 2FA', () => {
|
|
167
|
+
it('should return TOTP URI and backup codes when enabling 2FA', async () => {
|
|
168
|
+
const result = await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
169
|
+
|
|
170
|
+
expect(result.error).toBeNull();
|
|
171
|
+
expect(result.data).not.toBeNull();
|
|
172
|
+
expect(result.data?.totpURI).toContain('otpauth://totp/');
|
|
173
|
+
expect(result.data?.backupCodes).toHaveLength(5);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should extract secret from TOTP URI', async () => {
|
|
177
|
+
const result = await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
178
|
+
|
|
179
|
+
const totpUri = result.data?.totpURI;
|
|
180
|
+
const secretMatch = totpUri?.match(/secret=([A-Z2-7]+)/i);
|
|
181
|
+
expect(secretMatch).not.toBeNull();
|
|
182
|
+
expect(secretMatch?.[1]).toBe('JBSWY3DPEHPK3PXP');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('Verify TOTP', () => {
|
|
187
|
+
it('should verify valid TOTP code', async () => {
|
|
188
|
+
const result = await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
189
|
+
|
|
190
|
+
expect(result.error).toBeNull();
|
|
191
|
+
expect(result.data).not.toBeNull();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should reject invalid TOTP code', async () => {
|
|
195
|
+
const result = await authClient.twoFactor.verifyTotp({ code: '000000' });
|
|
196
|
+
|
|
197
|
+
expect(result.error).not.toBeNull();
|
|
198
|
+
expect(result.error?.message).toBe('Ungültiger Code');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should set twoFactorEnabled after successful verification', async () => {
|
|
202
|
+
await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
203
|
+
|
|
204
|
+
const session = authClient._getSession();
|
|
205
|
+
expect(session?.user.twoFactorEnabled).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('Disable 2FA', () => {
|
|
210
|
+
it('should disable 2FA with password', async () => {
|
|
211
|
+
// First enable 2FA
|
|
212
|
+
await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
213
|
+
await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
214
|
+
|
|
215
|
+
// Then disable
|
|
216
|
+
const result = await authClient.twoFactor.disable({ password: 'SecurePass123!' });
|
|
217
|
+
|
|
218
|
+
expect(result.error).toBeNull();
|
|
219
|
+
const session = authClient._getSession();
|
|
220
|
+
expect(session?.user.twoFactorEnabled).toBe(false);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('Backup Codes', () => {
|
|
225
|
+
it('should generate backup codes', async () => {
|
|
226
|
+
const result = await authClient.twoFactor.generateBackupCodes({ password: 'SecurePass123!' });
|
|
227
|
+
|
|
228
|
+
expect(result.error).toBeNull();
|
|
229
|
+
expect(result.data?.backupCodes).toHaveLength(5);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should verify backup code', async () => {
|
|
233
|
+
const result = await authClient.twoFactor.verifyBackupCode({ code: '12345678' });
|
|
234
|
+
|
|
235
|
+
expect(result.error).toBeNull();
|
|
236
|
+
expect(result.data).not.toBeNull();
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Test Suite: Passkey Management
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
describe('Passkey Management', () => {
|
|
246
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
247
|
+
|
|
248
|
+
beforeEach(async () => {
|
|
249
|
+
authClient = createMockAuthClient();
|
|
250
|
+
resetCookies();
|
|
251
|
+
// Login first
|
|
252
|
+
await authClient.signIn.email({
|
|
253
|
+
email: 'test@example.com',
|
|
254
|
+
password: 'SecurePass123!',
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should add a new passkey', async () => {
|
|
259
|
+
const passkeyName = 'My Laptop';
|
|
260
|
+
const result = await authClient.passkey.addPasskey({ name: passkeyName });
|
|
261
|
+
|
|
262
|
+
expect(result.error).toBeNull();
|
|
263
|
+
expect(result.data).not.toBeNull();
|
|
264
|
+
expect(result.data?.name).toBe(passkeyName);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should list user passkeys', async () => {
|
|
268
|
+
const result = await authClient.passkey.listUserPasskeys();
|
|
269
|
+
|
|
270
|
+
expect(result.error).toBeNull();
|
|
271
|
+
expect(result.data).toBeInstanceOf(Array);
|
|
272
|
+
expect(result.data?.length).toBeGreaterThan(0);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should delete a passkey', async () => {
|
|
276
|
+
const result = await authClient.passkey.deletePasskey({ id: 'passkey-123' });
|
|
277
|
+
|
|
278
|
+
expect(result.error).toBeNull();
|
|
279
|
+
expect(result.data).toBe(true);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// ============================================================================
|
|
284
|
+
// Test Suite: Error Translations
|
|
285
|
+
// ============================================================================
|
|
286
|
+
|
|
287
|
+
describe('Error Translations', () => {
|
|
288
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
289
|
+
|
|
290
|
+
beforeEach(() => {
|
|
291
|
+
authClient = createMockAuthClient();
|
|
292
|
+
resetCookies();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should return German error message for invalid credentials', async () => {
|
|
296
|
+
const result = await authClient.signIn.email({
|
|
297
|
+
email: 'invalid@test.com',
|
|
298
|
+
password: 'WrongPassword!',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(result.error?.message).toBe('Ungültige Anmeldedaten');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should return error code for backend errors', async () => {
|
|
305
|
+
const result = await authClient.signIn.email({
|
|
306
|
+
email: 'invalid@test.com',
|
|
307
|
+
password: 'WrongPassword!',
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(result.error?.code).toBe('LTNS_0010');
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// Test Suite: Complete Auth Flow
|
|
316
|
+
// ============================================================================
|
|
317
|
+
|
|
318
|
+
describe('Complete Auth Flow', () => {
|
|
319
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
320
|
+
|
|
321
|
+
beforeEach(() => {
|
|
322
|
+
authClient = createMockAuthClient();
|
|
323
|
+
resetCookies();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should complete: Register -> Enable 2FA -> Add Passkey', async () => {
|
|
327
|
+
// 1. Register
|
|
328
|
+
const registerResult = await authClient.signUp.email({
|
|
329
|
+
email: 'flow@test.com',
|
|
330
|
+
password: 'SecurePass123!',
|
|
331
|
+
name: 'Flow Test',
|
|
332
|
+
});
|
|
333
|
+
expect(registerResult.error).toBeNull();
|
|
334
|
+
expect(authClient._getSession()).not.toBeNull();
|
|
335
|
+
|
|
336
|
+
// 2. Enable 2FA
|
|
337
|
+
const enable2FAResult = await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
338
|
+
expect(enable2FAResult.error).toBeNull();
|
|
339
|
+
expect(enable2FAResult.data?.totpURI).toBeDefined();
|
|
340
|
+
|
|
341
|
+
// 3. Verify TOTP
|
|
342
|
+
const verifyResult = await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
343
|
+
expect(verifyResult.error).toBeNull();
|
|
344
|
+
expect(authClient._getSession()?.user.twoFactorEnabled).toBe(true);
|
|
345
|
+
|
|
346
|
+
// 4. Add Passkey
|
|
347
|
+
const passkeyResult = await authClient.passkey.addPasskey({ name: 'Test Device' });
|
|
348
|
+
expect(passkeyResult.error).toBeNull();
|
|
349
|
+
expect(passkeyResult.data?.name).toBe('Test Device');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should complete: Register -> Add Passkey -> Enable 2FA', async () => {
|
|
353
|
+
// 1. Register
|
|
354
|
+
const registerResult = await authClient.signUp.email({
|
|
355
|
+
email: 'flow2@test.com',
|
|
356
|
+
password: 'SecurePass123!',
|
|
357
|
+
name: 'Flow Test 2',
|
|
358
|
+
});
|
|
359
|
+
expect(registerResult.error).toBeNull();
|
|
360
|
+
|
|
361
|
+
// 2. Add Passkey first
|
|
362
|
+
const passkeyResult = await authClient.passkey.addPasskey({ name: 'Early Passkey' });
|
|
363
|
+
expect(passkeyResult.error).toBeNull();
|
|
364
|
+
|
|
365
|
+
// 3. Then enable 2FA
|
|
366
|
+
const enable2FAResult = await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
367
|
+
expect(enable2FAResult.error).toBeNull();
|
|
368
|
+
|
|
369
|
+
// 4. Verify TOTP
|
|
370
|
+
const verifyResult = await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
371
|
+
expect(verifyResult.error).toBeNull();
|
|
372
|
+
expect(authClient._getSession()?.user.twoFactorEnabled).toBe(true);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('should complete: Login -> Logout -> Login with 2FA', async () => {
|
|
376
|
+
// Setup: Register and enable 2FA
|
|
377
|
+
await authClient.signUp.email({
|
|
378
|
+
email: 'logout@test.com',
|
|
379
|
+
password: 'SecurePass123!',
|
|
380
|
+
name: 'Logout Test',
|
|
381
|
+
});
|
|
382
|
+
await authClient.twoFactor.enable({ password: 'SecurePass123!' });
|
|
383
|
+
await authClient.twoFactor.verifyTotp({ code: '123456' });
|
|
384
|
+
|
|
385
|
+
// 1. Logout
|
|
386
|
+
await authClient.signOut();
|
|
387
|
+
expect(authClient._getSession()).toBeNull();
|
|
388
|
+
|
|
389
|
+
// 2. Login again
|
|
390
|
+
const loginResult = await authClient.signIn.email({
|
|
391
|
+
email: 'logout@test.com',
|
|
392
|
+
password: 'SecurePass123!',
|
|
393
|
+
});
|
|
394
|
+
expect(loginResult.error).toBeNull();
|
|
395
|
+
|
|
396
|
+
// Note: In real flow, 2FA would be required here
|
|
397
|
+
// The mock simulates this by having twoFactorEnabled in the user object
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// ============================================================================
|
|
402
|
+
// Test Suite: Session Management
|
|
403
|
+
// ============================================================================
|
|
404
|
+
|
|
405
|
+
describe('Session Management', () => {
|
|
406
|
+
let authClient: ReturnType<typeof createMockAuthClient>;
|
|
407
|
+
|
|
408
|
+
beforeEach(() => {
|
|
409
|
+
authClient = createMockAuthClient();
|
|
410
|
+
resetCookies();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should start with no session', () => {
|
|
414
|
+
const session = authClient._getSession();
|
|
415
|
+
expect(session).toBeNull();
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('should create session on login', async () => {
|
|
419
|
+
await authClient.signIn.email({
|
|
420
|
+
email: 'test@example.com',
|
|
421
|
+
password: 'SecurePass123!',
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const session = authClient._getSession();
|
|
425
|
+
expect(session).not.toBeNull();
|
|
426
|
+
expect(session?.session.token).toBeDefined();
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('should preserve session data', async () => {
|
|
430
|
+
await authClient.signIn.email({
|
|
431
|
+
email: 'preserve@test.com',
|
|
432
|
+
password: 'SecurePass123!',
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
const session = authClient._getSession();
|
|
436
|
+
expect(session?.user.email).toBe('preserve@test.com');
|
|
437
|
+
expect(session?.session.id).toBe('session-123');
|
|
438
|
+
});
|
|
439
|
+
});
|