@umituz/react-native-auth 3.4.22 → 3.4.23
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 +1 -1
- package/src/__tests__/services/AnonymousModeService.test.ts +22 -153
- package/src/__tests__/services/AuthCoreInitialization.test.ts +45 -0
- package/src/__tests__/services/AuthCoreOperations.test.ts +71 -0
- package/src/__tests__/services/AuthPackage.test.ts +24 -171
- package/src/__tests__/utils/AuthDisplayNameValidation.test.ts +44 -0
- package/src/__tests__/utils/AuthEmailValidation.test.ts +38 -0
- package/src/__tests__/utils/AuthPasswordValidation.test.ts +90 -0
- package/src/index.ts +11 -95
- package/src/infrastructure/services/UserDocument.types.ts +44 -0
- package/src/infrastructure/services/UserDocumentService.ts +33 -106
- package/src/infrastructure/utils/AuthValidation.ts +37 -156
- package/src/__tests__/services/AuthCoreService.test.ts +0 -247
- package/src/__tests__/utils/AuthValidation.test.ts +0 -270
|
@@ -1,38 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Validation Utilities
|
|
3
|
-
* Single Responsibility: Email and password validation for authentication
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import type { PasswordConfig } from "../../domain/value-objects/AuthConfig";
|
|
7
2
|
import { getAuthPackage } from "../services/AuthPackage";
|
|
8
3
|
|
|
9
|
-
export interface ValidationResult {
|
|
10
|
-
|
|
11
|
-
error?: string; // This should be a localization key
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface PasswordStrengthResult extends ValidationResult {
|
|
15
|
-
requirements: PasswordRequirements;
|
|
16
|
-
}
|
|
17
|
-
|
|
4
|
+
export interface ValidationResult { isValid: boolean; error?: string; }
|
|
5
|
+
export interface PasswordStrengthResult extends ValidationResult { requirements: PasswordRequirements; }
|
|
18
6
|
export interface PasswordRequirements {
|
|
19
|
-
hasMinLength: boolean;
|
|
20
|
-
hasUppercase: boolean;
|
|
21
|
-
hasLowercase: boolean;
|
|
22
|
-
hasNumber: boolean;
|
|
23
|
-
hasSpecialChar: boolean;
|
|
7
|
+
hasMinLength: boolean; hasUppercase: boolean; hasLowercase: boolean; hasNumber: boolean; hasSpecialChar: boolean;
|
|
24
8
|
}
|
|
25
|
-
|
|
26
9
|
export interface ValidationConfig {
|
|
27
|
-
emailRegex: RegExp;
|
|
28
|
-
|
|
29
|
-
lowercaseRegex: RegExp;
|
|
30
|
-
numberRegex: RegExp;
|
|
31
|
-
specialCharRegex: RegExp;
|
|
32
|
-
displayNameMinLength: number;
|
|
10
|
+
emailRegex: RegExp; uppercaseRegex: RegExp; lowercaseRegex: RegExp;
|
|
11
|
+
numberRegex: RegExp; specialCharRegex: RegExp; displayNameMinLength: number;
|
|
33
12
|
}
|
|
34
13
|
|
|
35
|
-
const
|
|
14
|
+
const DEFAULT_VAL_CONFIG: ValidationConfig = {
|
|
36
15
|
emailRegex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
37
16
|
uppercaseRegex: /[A-Z]/,
|
|
38
17
|
lowercaseRegex: /[a-z]/,
|
|
@@ -41,155 +20,57 @@ const DEFAULT_VALIDATION_CONFIG: ValidationConfig = {
|
|
|
41
20
|
displayNameMinLength: 2,
|
|
42
21
|
};
|
|
43
22
|
|
|
44
|
-
function
|
|
45
|
-
const
|
|
23
|
+
function getValConfig(): ValidationConfig {
|
|
24
|
+
const p = getAuthPackage()?.getConfig();
|
|
46
25
|
return {
|
|
47
|
-
emailRegex:
|
|
48
|
-
uppercaseRegex:
|
|
49
|
-
lowercaseRegex:
|
|
50
|
-
numberRegex:
|
|
51
|
-
specialCharRegex:
|
|
52
|
-
displayNameMinLength:
|
|
26
|
+
emailRegex: p?.validation.emailRegex || DEFAULT_VAL_CONFIG.emailRegex,
|
|
27
|
+
uppercaseRegex: DEFAULT_VAL_CONFIG.uppercaseRegex,
|
|
28
|
+
lowercaseRegex: DEFAULT_VAL_CONFIG.lowercaseRegex,
|
|
29
|
+
numberRegex: DEFAULT_VAL_CONFIG.numberRegex,
|
|
30
|
+
specialCharRegex: DEFAULT_VAL_CONFIG.specialCharRegex,
|
|
31
|
+
displayNameMinLength: DEFAULT_VAL_CONFIG.displayNameMinLength,
|
|
53
32
|
};
|
|
54
33
|
}
|
|
55
34
|
|
|
56
|
-
/**
|
|
57
|
-
* Validate email format
|
|
58
|
-
*/
|
|
59
35
|
export function validateEmail(email: string): ValidationResult {
|
|
60
|
-
if (!email || email.trim() === "") {
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const config = getValidationConfig();
|
|
65
|
-
if (!config.emailRegex.test(email.trim())) {
|
|
66
|
-
return { isValid: false, error: "auth.validation.invalidEmail" };
|
|
67
|
-
}
|
|
68
|
-
|
|
36
|
+
if (!email || email.trim() === "") return { isValid: false, error: "auth.validation.emailRequired" };
|
|
37
|
+
if (!getValConfig().emailRegex.test(email.trim())) return { isValid: false, error: "auth.validation.invalidEmail" };
|
|
69
38
|
return { isValid: true };
|
|
70
39
|
}
|
|
71
40
|
|
|
72
|
-
/**
|
|
73
|
-
* Validate password for login - only checks if password is provided
|
|
74
|
-
* No strength requirements for login (existing users may have old passwords)
|
|
75
|
-
*/
|
|
76
41
|
export function validatePasswordForLogin(password: string): ValidationResult {
|
|
77
|
-
if (!password || password.length === 0) {
|
|
78
|
-
return { isValid: false, error: "auth.validation.passwordRequired" };
|
|
79
|
-
}
|
|
80
|
-
|
|
42
|
+
if (!password || password.length === 0) return { isValid: false, error: "auth.validation.passwordRequired" };
|
|
81
43
|
return { isValid: true };
|
|
82
44
|
}
|
|
83
45
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
*/
|
|
88
|
-
export function validatePasswordForRegister(
|
|
89
|
-
password: string,
|
|
90
|
-
config: PasswordConfig
|
|
91
|
-
): PasswordStrengthResult {
|
|
92
|
-
const validationConfig = getValidationConfig();
|
|
93
|
-
const requirements: PasswordRequirements = {
|
|
46
|
+
export function validatePasswordForRegister(password: string, config: PasswordConfig): PasswordStrengthResult {
|
|
47
|
+
const v = getValConfig();
|
|
48
|
+
const req: PasswordRequirements = {
|
|
94
49
|
hasMinLength: password.length >= config.minLength,
|
|
95
|
-
hasUppercase: !config.requireUppercase ||
|
|
96
|
-
hasLowercase: !config.requireLowercase ||
|
|
97
|
-
hasNumber: !config.requireNumber ||
|
|
98
|
-
hasSpecialChar:
|
|
99
|
-
!config.requireSpecialChar || validationConfig.specialCharRegex.test(password),
|
|
50
|
+
hasUppercase: !config.requireUppercase || v.uppercaseRegex.test(password),
|
|
51
|
+
hasLowercase: !config.requireLowercase || v.lowercaseRegex.test(password),
|
|
52
|
+
hasNumber: !config.requireNumber || v.numberRegex.test(password),
|
|
53
|
+
hasSpecialChar: !config.requireSpecialChar || v.specialCharRegex.test(password),
|
|
100
54
|
};
|
|
101
55
|
|
|
102
|
-
if (!password
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!requirements.hasMinLength) {
|
|
111
|
-
return {
|
|
112
|
-
isValid: false,
|
|
113
|
-
error: "auth.validation.passwordTooShort",
|
|
114
|
-
requirements,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (config.requireUppercase && !validationConfig.uppercaseRegex.test(password)) {
|
|
119
|
-
return {
|
|
120
|
-
isValid: false,
|
|
121
|
-
error: "auth.validation.passwordRequireUppercase",
|
|
122
|
-
requirements,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
56
|
+
if (!password) return { isValid: false, error: "auth.validation.passwordRequired", requirements: req };
|
|
57
|
+
if (!req.hasMinLength) return { isValid: false, error: "auth.validation.passwordTooShort", requirements: req };
|
|
58
|
+
if (config.requireUppercase && !req.hasUppercase) return { isValid: false, error: "auth.validation.passwordRequireUppercase", requirements: req };
|
|
59
|
+
if (config.requireLowercase && !req.hasLowercase) return { isValid: false, error: "auth.validation.passwordRequireLowercase", requirements: req };
|
|
60
|
+
if (config.requireNumber && !req.hasNumber) return { isValid: false, error: "auth.validation.passwordRequireNumber", requirements: req };
|
|
61
|
+
if (config.requireSpecialChar && !req.hasSpecialChar) return { isValid: false, error: "auth.validation.passwordRequireSpecialChar", requirements: req };
|
|
125
62
|
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
isValid: false,
|
|
129
|
-
error: "auth.validation.passwordRequireLowercase",
|
|
130
|
-
requirements,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (config.requireNumber && !validationConfig.numberRegex.test(password)) {
|
|
135
|
-
return {
|
|
136
|
-
isValid: false,
|
|
137
|
-
error: "auth.validation.passwordRequireNumber",
|
|
138
|
-
requirements,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (config.requireSpecialChar && !validationConfig.specialCharRegex.test(password)) {
|
|
143
|
-
return {
|
|
144
|
-
isValid: false,
|
|
145
|
-
error: "auth.validation.passwordRequireSpecialChar",
|
|
146
|
-
requirements,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return { isValid: true, requirements };
|
|
63
|
+
return { isValid: true, requirements: req };
|
|
151
64
|
}
|
|
152
65
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
export function validatePasswordConfirmation(
|
|
157
|
-
password: string,
|
|
158
|
-
confirmPassword: string
|
|
159
|
-
): ValidationResult {
|
|
160
|
-
if (!confirmPassword) {
|
|
161
|
-
return { isValid: false, error: "auth.validation.confirmPasswordRequired" };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (password !== confirmPassword) {
|
|
165
|
-
return { isValid: false, error: "auth.validation.passwordsDoNotMatch" };
|
|
166
|
-
}
|
|
167
|
-
|
|
66
|
+
export function validatePasswordConfirmation(password: string, confirm: string): ValidationResult {
|
|
67
|
+
if (!confirm) return { isValid: false, error: "auth.validation.confirmPasswordRequired" };
|
|
68
|
+
if (password !== confirm) return { isValid: false, error: "auth.validation.passwordsDoNotMatch" };
|
|
168
69
|
return { isValid: true };
|
|
169
70
|
}
|
|
170
71
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
export function validateDisplayName(
|
|
175
|
-
displayName: string,
|
|
176
|
-
minLength?: number
|
|
177
|
-
): ValidationResult {
|
|
178
|
-
if (!displayName || displayName.trim() === "") {
|
|
179
|
-
return { isValid: false, error: "auth.validation.nameRequired" };
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const config = getValidationConfig();
|
|
183
|
-
const actualMinLength = minLength ?? config.displayNameMinLength;
|
|
184
|
-
|
|
185
|
-
if (displayName.trim().length < actualMinLength) {
|
|
186
|
-
return {
|
|
187
|
-
isValid: false,
|
|
188
|
-
error: "auth.validation.nameTooShort",
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
72
|
+
export function validateDisplayName(name: string, minLength?: number): ValidationResult {
|
|
73
|
+
if (!name || name.trim() === "") return { isValid: false, error: "auth.validation.nameRequired" };
|
|
74
|
+
if (name.trim().length < (minLength ?? getValConfig().displayNameMinLength)) return { isValid: false, error: "auth.validation.nameTooShort" };
|
|
192
75
|
return { isValid: true };
|
|
193
76
|
}
|
|
194
|
-
|
|
195
|
-
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AuthCoreService Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { AuthCoreService } from '../../../src/infrastructure/services/AuthCoreService';
|
|
6
|
-
import { DEFAULT_AUTH_CONFIG } from '../../../src/domain/value-objects/AuthConfig';
|
|
7
|
-
import type { IAuthProvider } from '../../../src/application/ports/IAuthProvider';
|
|
8
|
-
import type { AuthUser } from '../../../src/domain/entities/AuthUser';
|
|
9
|
-
|
|
10
|
-
describe('AuthCoreService', () => {
|
|
11
|
-
let authCoreService: AuthCoreService;
|
|
12
|
-
let mockProvider: jest.Mocked<IAuthProvider>;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
mockProvider = {
|
|
16
|
-
initialize: jest.fn(),
|
|
17
|
-
isInitialized: jest.fn().mockReturnValue(true),
|
|
18
|
-
signIn: jest.fn(),
|
|
19
|
-
signUp: jest.fn(),
|
|
20
|
-
signOut: jest.fn(),
|
|
21
|
-
getCurrentUser: jest.fn(),
|
|
22
|
-
onAuthStateChange: jest.fn().mockReturnValue(jest.fn()),
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
authCoreService = new AuthCoreService(DEFAULT_AUTH_CONFIG);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('constructor', () => {
|
|
29
|
-
it('should initialize with provided config', () => {
|
|
30
|
-
const customConfig = {
|
|
31
|
-
...DEFAULT_AUTH_CONFIG,
|
|
32
|
-
password: {
|
|
33
|
-
...DEFAULT_AUTH_CONFIG.password,
|
|
34
|
-
minLength: 12,
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const service = new AuthCoreService(customConfig);
|
|
39
|
-
expect(service.getConfig()).toEqual(customConfig);
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('initialize', () => {
|
|
44
|
-
it('should initialize with IAuthProvider', async () => {
|
|
45
|
-
await authCoreService.initialize(mockProvider);
|
|
46
|
-
expect(mockProvider.initialize).toHaveBeenCalled();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should initialize with Firebase Auth instance', async () => {
|
|
50
|
-
const mockFirebaseAuth = {
|
|
51
|
-
currentUser: null,
|
|
52
|
-
} as any;
|
|
53
|
-
|
|
54
|
-
await expect(authCoreService.initialize(mockFirebaseAuth)).rejects.toThrow();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should throw error when no provider provided', async () => {
|
|
58
|
-
await expect(authCoreService.initialize(null as any)).rejects.toThrow(
|
|
59
|
-
'Auth provider or Firebase Auth instance is required'
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('isInitialized', () => {
|
|
65
|
-
it('should return false when not initialized', () => {
|
|
66
|
-
expect(authCoreService.isInitialized()).toBe(false);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should return true when initialized', async () => {
|
|
70
|
-
await authCoreService.initialize(mockProvider);
|
|
71
|
-
expect(authCoreService.isInitialized()).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('signUp', () => {
|
|
76
|
-
const mockUser: AuthUser = {
|
|
77
|
-
uid: 'test-uid',
|
|
78
|
-
email: 'test@example.com',
|
|
79
|
-
displayName: 'Test User',
|
|
80
|
-
isAnonymous: false,
|
|
81
|
-
emailVerified: false,
|
|
82
|
-
photoURL: null,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
beforeEach(async () => {
|
|
86
|
-
await authCoreService.initialize(mockProvider);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should sign up successfully with valid credentials', async () => {
|
|
90
|
-
mockProvider.signUp.mockResolvedValue(mockUser);
|
|
91
|
-
|
|
92
|
-
const result = await authCoreService.signUp({
|
|
93
|
-
email: 'test@example.com',
|
|
94
|
-
password: 'password123',
|
|
95
|
-
displayName: 'Test User',
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
expect(result).toEqual(mockUser);
|
|
99
|
-
expect(mockProvider.signUp).toHaveBeenCalledWith({
|
|
100
|
-
email: 'test@example.com',
|
|
101
|
-
password: 'password123',
|
|
102
|
-
displayName: 'Test User',
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should sign up without display name', async () => {
|
|
107
|
-
mockProvider.signUp.mockResolvedValue(mockUser);
|
|
108
|
-
|
|
109
|
-
await authCoreService.signUp({
|
|
110
|
-
email: 'test@example.com',
|
|
111
|
-
password: 'password123',
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(mockProvider.signUp).toHaveBeenCalledWith({
|
|
115
|
-
email: 'test@example.com',
|
|
116
|
-
password: 'password123',
|
|
117
|
-
displayName: undefined,
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should throw error when not initialized', async () => {
|
|
122
|
-
const uninitializedService = new AuthCoreService(DEFAULT_AUTH_CONFIG);
|
|
123
|
-
|
|
124
|
-
await expect(uninitializedService.signUp({
|
|
125
|
-
email: 'test@example.com',
|
|
126
|
-
password: 'password123',
|
|
127
|
-
})).rejects.toThrow('Auth service is not initialized');
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('signIn', () => {
|
|
132
|
-
const mockUser: AuthUser = {
|
|
133
|
-
uid: 'test-uid',
|
|
134
|
-
email: 'test@example.com',
|
|
135
|
-
displayName: 'Test User',
|
|
136
|
-
isAnonymous: false,
|
|
137
|
-
emailVerified: false,
|
|
138
|
-
photoURL: null,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
beforeEach(async () => {
|
|
142
|
-
await authCoreService.initialize(mockProvider);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should sign in successfully with valid credentials', async () => {
|
|
146
|
-
mockProvider.signIn.mockResolvedValue(mockUser);
|
|
147
|
-
|
|
148
|
-
const result = await authCoreService.signIn({
|
|
149
|
-
email: 'test@example.com',
|
|
150
|
-
password: 'password123',
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(result).toEqual(mockUser);
|
|
154
|
-
expect(mockProvider.signIn).toHaveBeenCalledWith({
|
|
155
|
-
email: 'test@example.com',
|
|
156
|
-
password: 'password123',
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('should throw error when not initialized', async () => {
|
|
161
|
-
const uninitializedService = new AuthCoreService(DEFAULT_AUTH_CONFIG);
|
|
162
|
-
|
|
163
|
-
await expect(uninitializedService.signIn({
|
|
164
|
-
email: 'test@example.com',
|
|
165
|
-
password: 'password123',
|
|
166
|
-
})).rejects.toThrow('Auth service is not initialized');
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('signOut', () => {
|
|
171
|
-
beforeEach(async () => {
|
|
172
|
-
await authCoreService.initialize(mockProvider);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('should sign out successfully', async () => {
|
|
176
|
-
await authCoreService.signOut();
|
|
177
|
-
expect(mockProvider.signOut).toHaveBeenCalled();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should handle sign out when not initialized', async () => {
|
|
181
|
-
const uninitializedService = new AuthCoreService(DEFAULT_AUTH_CONFIG);
|
|
182
|
-
|
|
183
|
-
await expect(uninitializedService.signOut()).resolves.not.toThrow();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
describe('getCurrentUser', () => {
|
|
188
|
-
const mockUser: AuthUser = {
|
|
189
|
-
uid: 'test-uid',
|
|
190
|
-
email: 'test@example.com',
|
|
191
|
-
displayName: 'Test User',
|
|
192
|
-
isAnonymous: false,
|
|
193
|
-
emailVerified: false,
|
|
194
|
-
photoURL: null,
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
it('should return null when not initialized', () => {
|
|
198
|
-
const result = authCoreService.getCurrentUser();
|
|
199
|
-
expect(result).toBeNull();
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('should return current user when initialized', async () => {
|
|
203
|
-
mockProvider.getCurrentUser.mockReturnValue(mockUser);
|
|
204
|
-
await authCoreService.initialize(mockProvider);
|
|
205
|
-
|
|
206
|
-
const result = authCoreService.getCurrentUser();
|
|
207
|
-
expect(result).toEqual(mockUser);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('should return null when no current user', async () => {
|
|
211
|
-
mockProvider.getCurrentUser.mockReturnValue(null);
|
|
212
|
-
await authCoreService.initialize(mockProvider);
|
|
213
|
-
|
|
214
|
-
const result = authCoreService.getCurrentUser();
|
|
215
|
-
expect(result).toBeNull();
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe('onAuthStateChange', () => {
|
|
220
|
-
it('should return cleanup function when not initialized', () => {
|
|
221
|
-
const callback = jest.fn();
|
|
222
|
-
const cleanup = authCoreService.onAuthStateChange(callback);
|
|
223
|
-
|
|
224
|
-
expect(callback).toHaveBeenCalledWith(null);
|
|
225
|
-
expect(typeof cleanup).toBe('function');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
it('should subscribe to auth state changes when initialized', async () => {
|
|
229
|
-
const callback = jest.fn();
|
|
230
|
-
const mockCleanup = jest.fn();
|
|
231
|
-
mockProvider.onAuthStateChange.mockReturnValue(mockCleanup);
|
|
232
|
-
|
|
233
|
-
await authCoreService.initialize(mockProvider);
|
|
234
|
-
const cleanup = authCoreService.onAuthStateChange(callback);
|
|
235
|
-
|
|
236
|
-
expect(mockProvider.onAuthStateChange).toHaveBeenCalledWith(callback);
|
|
237
|
-
expect(cleanup).toBe(mockCleanup);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('getConfig', () => {
|
|
242
|
-
it('should return the current config', () => {
|
|
243
|
-
const config = authCoreService.getConfig();
|
|
244
|
-
expect(config).toEqual(DEFAULT_AUTH_CONFIG);
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
});
|