@oxyhq/services 5.7.5 → 5.8.2
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/README.md +76 -76
- package/lib/commonjs/core/index.js +177 -102
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +69 -28
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/Avatar.js +15 -6
- package/lib/commonjs/ui/components/Avatar.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +100 -12
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedItem.js +58 -13
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedSection.js +7 -1
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +356 -0
- package/lib/commonjs/ui/components/Header.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +28 -7
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/index.js +7 -0
- package/lib/commonjs/ui/components/index.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +606 -546
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.md +436 -0
- package/lib/commonjs/ui/context/OxyContext.js +181 -199
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/index.js +6 -0
- package/lib/commonjs/ui/hooks/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.js +59 -2
- package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js +11 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
- package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1160 -406
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +214 -37
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +90 -0
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
- package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
- package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +9 -6
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -30
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +37 -46
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +36 -6
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/stores/followStore.js +106 -1
- package/lib/commonjs/ui/stores/followStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +337 -0
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
- package/lib/commonjs/ui/styles/index.js +11 -0
- package/lib/commonjs/ui/styles/index.js.map +1 -1
- package/lib/module/core/index.js +177 -41
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +24 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/Avatar.js +15 -6
- package/lib/module/ui/components/Avatar.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +101 -13
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/GroupedItem.js +59 -14
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/GroupedSection.js +7 -1
- package/lib/module/ui/components/GroupedSection.js.map +1 -1
- package/lib/module/ui/components/Header.js +351 -0
- package/lib/module/ui/components/Header.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +30 -9
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/index.js +1 -0
- package/lib/module/ui/components/index.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +607 -547
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.md +436 -0
- package/lib/module/ui/context/OxyContext.js +180 -198
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/index.js +1 -1
- package/lib/module/ui/hooks/index.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.js +57 -1
- package/lib/module/ui/hooks/useFollow.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +5 -2
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/navigation/OxyRouter.js +11 -1
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
- package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +1161 -407
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +248 -465
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +3 -3
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +214 -37
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +32 -305
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +5 -5
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +85 -0
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -0
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
- package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
- package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +9 -6
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -30
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +37 -46
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +36 -6
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/stores/followStore.js +106 -1
- package/lib/module/ui/stores/followStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +332 -0
- package/lib/module/ui/styles/authStyles.js.map +1 -0
- package/lib/module/ui/styles/index.js +1 -0
- package/lib/module/ui/styles/index.js.map +1 -1
- package/lib/typescript/core/index.d.ts +68 -24
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +13 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/ui/components/FollowButton.d.ts +1 -0
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
- package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +24 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -0
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/index.d.ts +1 -0
- package/lib/typescript/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useFollow.d.ts +20 -0
- package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/types.d.ts +9 -2
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts +15 -0
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +3 -1
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/stores/followStore.d.ts +10 -0
- package/lib/typescript/ui/stores/followStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
- package/lib/typescript/ui/styles/index.d.ts +1 -0
- package/lib/typescript/ui/styles/index.d.ts.map +1 -1
- package/package.json +1 -4
- package/src/core/index.ts +195 -41
- package/src/index.ts +64 -4
- package/src/ui/components/Avatar.tsx +11 -5
- package/src/ui/components/FollowButton.tsx +95 -11
- package/src/ui/components/GroupedItem.tsx +57 -9
- package/src/ui/components/GroupedSection.tsx +12 -0
- package/src/ui/components/Header.tsx +405 -0
- package/src/ui/components/OxyProvider.tsx +37 -15
- package/src/ui/components/index.ts +1 -0
- package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
- package/src/ui/components/internal/TextField.md +436 -0
- package/src/ui/components/internal/TextField.tsx +720 -620
- package/src/ui/context/OxyContext.tsx +211 -195
- package/src/ui/hooks/index.ts +1 -1
- package/src/ui/hooks/useFollow.ts +63 -0
- package/src/ui/hooks/useSessionSocket.ts +5 -2
- package/src/ui/navigation/OxyRouter.tsx +11 -1
- package/src/ui/navigation/types.ts +10 -2
- package/src/ui/screens/AccountCenterScreen.tsx +5 -5
- package/src/ui/screens/AccountManagementDemo.tsx +9 -9
- package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
- package/src/ui/screens/AccountSettingsScreen.tsx +1173 -403
- package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
- package/src/ui/screens/AppInfoScreen.tsx +270 -497
- package/src/ui/screens/FeedbackScreen.tsx +3 -3
- package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
- package/src/ui/screens/ProfileScreen.tsx +196 -33
- package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
- package/src/ui/screens/SessionManagementScreen.tsx +14 -22
- package/src/ui/screens/SignInScreen.tsx +27 -294
- package/src/ui/screens/SignUpScreen.tsx +5 -5
- package/src/ui/screens/UserLinksScreen.tsx +96 -0
- package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
- package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
- package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
- package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +9 -2
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -20
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +40 -24
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +9 -3
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +9 -3
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +9 -3
- package/src/ui/stores/authStore.ts +34 -7
- package/src/ui/stores/followStore.ts +102 -1
- package/src/ui/styles/authStyles.ts +352 -0
- package/src/ui/styles/index.ts +1 -0
- package/lib/commonjs/core/auth-manager.js +0 -440
- package/lib/commonjs/core/auth-manager.js.map +0 -1
- package/lib/commonjs/core/use-auth.js +0 -244
- package/lib/commonjs/core/use-auth.js.map +0 -1
- package/lib/module/core/auth-manager.js +0 -432
- package/lib/module/core/auth-manager.js.map +0 -1
- package/lib/module/core/use-auth.js +0 -235
- package/lib/module/core/use-auth.js.map +0 -1
- package/lib/typescript/core/auth-manager.d.ts +0 -136
- package/lib/typescript/core/auth-manager.d.ts.map +0 -1
- package/lib/typescript/core/use-auth.d.ts +0 -79
- package/lib/typescript/core/use-auth.d.ts.map +0 -1
- package/src/__tests__/middleware.test.ts +0 -105
- package/src/__tests__/setup.ts +0 -10
- package/src/__tests__/zero-config-auth.test.ts +0 -607
- package/src/core/auth-manager.ts +0 -500
- package/src/core/use-auth.tsx +0 -245
|
@@ -1,607 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Comprehensive test suite for Zero-Config Authentication
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { AuthenticationManager } from '../core/auth-manager';
|
|
6
|
-
import { authenticateRequest, OxyRequest } from '../../api/src/middleware/zero-config-auth';
|
|
7
|
-
import jwt from 'jsonwebtoken';
|
|
8
|
-
|
|
9
|
-
// Mock AsyncStorage for React Native
|
|
10
|
-
const mockAsyncStorage = {
|
|
11
|
-
getItem: jest.fn(),
|
|
12
|
-
setItem: jest.fn(),
|
|
13
|
-
removeItem: jest.fn(),
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);
|
|
17
|
-
|
|
18
|
-
// Mock axios
|
|
19
|
-
const mockAxiosInstance = {
|
|
20
|
-
get: jest.fn(),
|
|
21
|
-
post: jest.fn(),
|
|
22
|
-
put: jest.fn(),
|
|
23
|
-
delete: jest.fn(),
|
|
24
|
-
interceptors: {
|
|
25
|
-
request: { use: jest.fn() },
|
|
26
|
-
response: { use: jest.fn() }
|
|
27
|
-
},
|
|
28
|
-
defaults: { baseURL: 'http://localhost:3001' }
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
jest.mock('axios', () => ({
|
|
32
|
-
create: jest.fn(() => mockAxiosInstance),
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
describe('AuthenticationManager', () => {
|
|
36
|
-
let authManager: AuthenticationManager;
|
|
37
|
-
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
jest.clearAllMocks();
|
|
40
|
-
authManager = new AuthenticationManager('http://localhost:3001');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('initialization', () => {
|
|
44
|
-
it('should create axios client with correct config', () => {
|
|
45
|
-
expect(require('axios').create).toHaveBeenCalledWith({
|
|
46
|
-
baseURL: 'http://localhost:3001',
|
|
47
|
-
timeout: 15000,
|
|
48
|
-
withCredentials: true,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should setup request and response interceptors', () => {
|
|
53
|
-
expect(mockAxiosInstance.interceptors.request.use).toHaveBeenCalled();
|
|
54
|
-
expect(mockAxiosInstance.interceptors.response.use).toHaveBeenCalled();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should attempt to initialize from storage', async () => {
|
|
58
|
-
expect(mockAsyncStorage.getItem).toHaveBeenCalledWith('@oxy/auth-tokens');
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('login', () => {
|
|
63
|
-
const mockLoginResponse = {
|
|
64
|
-
data: {
|
|
65
|
-
success: true,
|
|
66
|
-
accessToken: 'mock-access-token',
|
|
67
|
-
refreshToken: 'mock-refresh-token',
|
|
68
|
-
user: { id: 'user123', username: 'testuser' }
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
mockAxiosInstance.post.mockResolvedValue(mockLoginResponse);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should successfully login with valid credentials', async () => {
|
|
77
|
-
const result = await authManager.login({ username: 'test', password: 'pass' });
|
|
78
|
-
|
|
79
|
-
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/auth/login', {
|
|
80
|
-
username: 'test',
|
|
81
|
-
password: 'pass'
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
expect(result).toEqual(mockLoginResponse.data);
|
|
85
|
-
expect(mockAsyncStorage.setItem).toHaveBeenCalledWith(
|
|
86
|
-
'@oxy/auth-tokens',
|
|
87
|
-
JSON.stringify({
|
|
88
|
-
accessToken: 'mock-access-token',
|
|
89
|
-
refreshToken: 'mock-refresh-token'
|
|
90
|
-
})
|
|
91
|
-
);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should throw error for invalid credentials', async () => {
|
|
95
|
-
mockAxiosInstance.post.mockRejectedValue(new Error('Invalid credentials'));
|
|
96
|
-
|
|
97
|
-
await expect(authManager.login({ username: 'test', password: 'wrong' }))
|
|
98
|
-
.rejects.toThrow('Invalid credentials');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should handle server error responses', async () => {
|
|
102
|
-
const errorResponse = {
|
|
103
|
-
response: {
|
|
104
|
-
data: { message: 'Server error occurred' },
|
|
105
|
-
status: 500
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
mockAxiosInstance.post.mockRejectedValue(errorResponse);
|
|
109
|
-
|
|
110
|
-
await expect(authManager.login({ username: 'test', password: 'pass' }))
|
|
111
|
-
.rejects.toThrow('Server error occurred');
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('register', () => {
|
|
116
|
-
const mockRegisterResponse = {
|
|
117
|
-
data: {
|
|
118
|
-
success: true,
|
|
119
|
-
accessToken: 'mock-access-token',
|
|
120
|
-
refreshToken: 'mock-refresh-token',
|
|
121
|
-
user: { id: 'user123', username: 'newuser', email: 'new@test.com' }
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
beforeEach(() => {
|
|
126
|
-
mockAxiosInstance.post.mockResolvedValue(mockRegisterResponse);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should successfully register new user', async () => {
|
|
130
|
-
const userData = {
|
|
131
|
-
username: 'newuser',
|
|
132
|
-
email: 'new@test.com',
|
|
133
|
-
password: 'password123'
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const result = await authManager.register(userData);
|
|
137
|
-
|
|
138
|
-
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/auth/register', userData);
|
|
139
|
-
expect(result).toEqual(mockRegisterResponse.data);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should handle registration errors', async () => {
|
|
143
|
-
const errorResponse = {
|
|
144
|
-
response: {
|
|
145
|
-
data: { message: 'Username already exists' },
|
|
146
|
-
status: 400
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
mockAxiosInstance.post.mockRejectedValue(errorResponse);
|
|
150
|
-
|
|
151
|
-
await expect(authManager.register({
|
|
152
|
-
username: 'existing',
|
|
153
|
-
email: 'test@test.com',
|
|
154
|
-
password: 'pass'
|
|
155
|
-
})).rejects.toThrow('Username already exists');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
describe('logout', () => {
|
|
160
|
-
beforeEach(() => {
|
|
161
|
-
mockAxiosInstance.post.mockResolvedValue({ data: { success: true } });
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should successfully logout and clear tokens', async () => {
|
|
165
|
-
// Set some tokens first
|
|
166
|
-
(authManager as any).tokens = {
|
|
167
|
-
accessToken: 'token1',
|
|
168
|
-
refreshToken: 'token2'
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
await authManager.logout();
|
|
172
|
-
|
|
173
|
-
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/auth/logout', {
|
|
174
|
-
refreshToken: 'token2'
|
|
175
|
-
});
|
|
176
|
-
expect(mockAsyncStorage.removeItem).toHaveBeenCalledWith('@oxy/auth-tokens');
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('should clear tokens even if server logout fails', async () => {
|
|
180
|
-
mockAxiosInstance.post.mockRejectedValue(new Error('Server error'));
|
|
181
|
-
|
|
182
|
-
(authManager as any).tokens = {
|
|
183
|
-
accessToken: 'token1',
|
|
184
|
-
refreshToken: 'token2'
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
await authManager.logout();
|
|
188
|
-
|
|
189
|
-
expect(mockAsyncStorage.removeItem).toHaveBeenCalledWith('@oxy/auth-tokens');
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe('getAuthState', () => {
|
|
194
|
-
it('should return unauthenticated state initially', () => {
|
|
195
|
-
const state = authManager.getAuthState();
|
|
196
|
-
|
|
197
|
-
expect(state).toEqual({
|
|
198
|
-
isAuthenticated: false,
|
|
199
|
-
user: null,
|
|
200
|
-
tokens: null
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('should return authenticated state when tokens are present', () => {
|
|
205
|
-
(authManager as any).tokens = {
|
|
206
|
-
accessToken: 'token1',
|
|
207
|
-
refreshToken: 'token2'
|
|
208
|
-
};
|
|
209
|
-
(authManager as any).user = { id: 'user123', username: 'test' };
|
|
210
|
-
|
|
211
|
-
const state = authManager.getAuthState();
|
|
212
|
-
|
|
213
|
-
expect(state.isAuthenticated).toBe(true);
|
|
214
|
-
expect(state.user).toEqual({ id: 'user123', username: 'test' });
|
|
215
|
-
expect(state.tokens).toEqual({
|
|
216
|
-
accessToken: 'token1',
|
|
217
|
-
refreshToken: 'token2'
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
describe('onAuthStateChange', () => {
|
|
223
|
-
it('should call callback immediately with current state', () => {
|
|
224
|
-
const callback = jest.fn();
|
|
225
|
-
|
|
226
|
-
authManager.onAuthStateChange(callback);
|
|
227
|
-
|
|
228
|
-
expect(callback).toHaveBeenCalledWith({
|
|
229
|
-
isAuthenticated: false,
|
|
230
|
-
user: null,
|
|
231
|
-
tokens: null
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('should return unsubscribe function', () => {
|
|
236
|
-
const callback = jest.fn();
|
|
237
|
-
|
|
238
|
-
const unsubscribe = authManager.onAuthStateChange(callback);
|
|
239
|
-
|
|
240
|
-
expect(typeof unsubscribe).toBe('function');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('should notify listeners on state changes', () => {
|
|
244
|
-
const callback = jest.fn();
|
|
245
|
-
authManager.onAuthStateChange(callback);
|
|
246
|
-
|
|
247
|
-
callback.mockClear();
|
|
248
|
-
|
|
249
|
-
// Simulate state change
|
|
250
|
-
(authManager as any).tokens = { accessToken: 'new-token', refreshToken: 'new-refresh' };
|
|
251
|
-
(authManager as any).notifyStateChange();
|
|
252
|
-
|
|
253
|
-
expect(callback).toHaveBeenCalledWith({
|
|
254
|
-
isAuthenticated: true,
|
|
255
|
-
user: null,
|
|
256
|
-
tokens: { accessToken: 'new-token', refreshToken: 'new-refresh' }
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe('username and email validation', () => {
|
|
262
|
-
it('should check username availability', async () => {
|
|
263
|
-
const mockResponse = { data: { available: true, message: 'Username available' } };
|
|
264
|
-
mockAxiosInstance.get.mockResolvedValue(mockResponse);
|
|
265
|
-
|
|
266
|
-
const result = await authManager.checkUsernameAvailability('newuser');
|
|
267
|
-
|
|
268
|
-
expect(mockAxiosInstance.get).toHaveBeenCalledWith('/auth/check-username/newuser');
|
|
269
|
-
expect(result).toEqual({ available: true, message: 'Username available' });
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('should check email availability', async () => {
|
|
273
|
-
const mockResponse = { data: { available: false, message: 'Email already registered' } };
|
|
274
|
-
mockAxiosInstance.post.mockResolvedValue(mockResponse);
|
|
275
|
-
|
|
276
|
-
const result = await authManager.checkEmailAvailability('test@example.com');
|
|
277
|
-
|
|
278
|
-
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/auth/check-email', {
|
|
279
|
-
email: 'test@example.com'
|
|
280
|
-
});
|
|
281
|
-
expect(result).toEqual({ available: false, message: 'Email already registered' });
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('should handle validation errors gracefully', async () => {
|
|
285
|
-
const errorResponse = {
|
|
286
|
-
response: {
|
|
287
|
-
status: 400,
|
|
288
|
-
data: { available: false, message: 'Invalid username format' }
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
mockAxiosInstance.get.mockRejectedValue(errorResponse);
|
|
292
|
-
|
|
293
|
-
const result = await authManager.checkUsernameAvailability('invalid@user');
|
|
294
|
-
|
|
295
|
-
expect(result).toEqual({ available: false, message: 'Invalid username format' });
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
describe('Zero-Config Backend Middleware', () => {
|
|
301
|
-
let mockReq: Partial<OxyRequest>;
|
|
302
|
-
let mockRes: any;
|
|
303
|
-
let mockNext: jest.Mock;
|
|
304
|
-
|
|
305
|
-
beforeEach(() => {
|
|
306
|
-
mockReq = {
|
|
307
|
-
headers: {},
|
|
308
|
-
cookies: {}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
mockRes = {
|
|
312
|
-
status: jest.fn().mockReturnThis(),
|
|
313
|
-
json: jest.fn()
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
mockNext = jest.fn();
|
|
317
|
-
|
|
318
|
-
// Mock JWT secret
|
|
319
|
-
process.env.ACCESS_TOKEN_SECRET = 'test-secret';
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
afterEach(() => {
|
|
323
|
-
delete process.env.ACCESS_TOKEN_SECRET;
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
describe('authenticateRequest', () => {
|
|
327
|
-
it('should require authentication by default', async () => {
|
|
328
|
-
const middleware = authenticateRequest();
|
|
329
|
-
|
|
330
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
331
|
-
|
|
332
|
-
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
333
|
-
expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
334
|
-
success: false,
|
|
335
|
-
error: 'MISSING_TOKEN',
|
|
336
|
-
message: 'Authentication required'
|
|
337
|
-
}));
|
|
338
|
-
expect(mockNext).not.toHaveBeenCalled();
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('should allow optional authentication', async () => {
|
|
342
|
-
const middleware = authenticateRequest({ required: false });
|
|
343
|
-
|
|
344
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
345
|
-
|
|
346
|
-
expect(mockNext).toHaveBeenCalled();
|
|
347
|
-
expect(mockRes.status).not.toHaveBeenCalled();
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it('should validate JWT tokens', async () => {
|
|
351
|
-
const token = jwt.sign(
|
|
352
|
-
{ id: 'user123', userId: 'user123', username: 'test' },
|
|
353
|
-
'test-secret',
|
|
354
|
-
{ expiresIn: '1h' }
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
mockReq.headers!.authorization = `Bearer ${token}`;
|
|
358
|
-
|
|
359
|
-
// Mock User.findById
|
|
360
|
-
const mockUser = {
|
|
361
|
-
_id: 'user123',
|
|
362
|
-
id: 'user123',
|
|
363
|
-
username: 'test',
|
|
364
|
-
email: 'test@example.com'
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
jest.mock('../../api/src/models/User', () => ({
|
|
368
|
-
findById: jest.fn().mockReturnValue({
|
|
369
|
-
select: jest.fn().mockResolvedValue(mockUser)
|
|
370
|
-
})
|
|
371
|
-
}));
|
|
372
|
-
|
|
373
|
-
const middleware = authenticateRequest();
|
|
374
|
-
|
|
375
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
376
|
-
|
|
377
|
-
expect(mockReq.userId).toBe('user123');
|
|
378
|
-
expect(mockNext).toHaveBeenCalled();
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it('should handle expired tokens', async () => {
|
|
382
|
-
const expiredToken = jwt.sign(
|
|
383
|
-
{ id: 'user123', userId: 'user123', username: 'test' },
|
|
384
|
-
'test-secret',
|
|
385
|
-
{ expiresIn: '-1h' } // Expired
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
mockReq.headers!.authorization = `Bearer ${expiredToken}`;
|
|
389
|
-
|
|
390
|
-
const middleware = authenticateRequest();
|
|
391
|
-
|
|
392
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
393
|
-
|
|
394
|
-
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
395
|
-
expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
396
|
-
error: 'TOKEN_EXPIRED',
|
|
397
|
-
message: 'Token has expired'
|
|
398
|
-
}));
|
|
399
|
-
expect(mockNext).not.toHaveBeenCalled();
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
it('should handle invalid tokens', async () => {
|
|
403
|
-
mockReq.headers!.authorization = 'Bearer invalid-token';
|
|
404
|
-
|
|
405
|
-
const middleware = authenticateRequest();
|
|
406
|
-
|
|
407
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
408
|
-
|
|
409
|
-
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
410
|
-
expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
411
|
-
error: 'INVALID_TOKEN',
|
|
412
|
-
message: 'Invalid token'
|
|
413
|
-
}));
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('should call custom error handler when provided', async () => {
|
|
417
|
-
const customErrorHandler = jest.fn();
|
|
418
|
-
const middleware = authenticateRequest({ onError: customErrorHandler });
|
|
419
|
-
|
|
420
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
421
|
-
|
|
422
|
-
expect(customErrorHandler).toHaveBeenCalledWith(
|
|
423
|
-
expect.objectContaining({
|
|
424
|
-
code: 'MISSING_TOKEN',
|
|
425
|
-
statusCode: 401
|
|
426
|
-
}),
|
|
427
|
-
mockReq,
|
|
428
|
-
mockRes
|
|
429
|
-
);
|
|
430
|
-
expect(mockRes.status).not.toHaveBeenCalled();
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
it('should skip authentication when skipIf condition is met', async () => {
|
|
434
|
-
const skipCondition = jest.fn().mockReturnValue(true);
|
|
435
|
-
const middleware = authenticateRequest({ skipIf: skipCondition });
|
|
436
|
-
|
|
437
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
438
|
-
|
|
439
|
-
expect(skipCondition).toHaveBeenCalledWith(mockReq);
|
|
440
|
-
expect(mockNext).toHaveBeenCalled();
|
|
441
|
-
expect(mockRes.status).not.toHaveBeenCalled();
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
describe('token extraction', () => {
|
|
446
|
-
it('should extract token from Authorization header', async () => {
|
|
447
|
-
const token = jwt.sign(
|
|
448
|
-
{ id: 'user123', userId: 'user123', username: 'test' },
|
|
449
|
-
'test-secret',
|
|
450
|
-
{ expiresIn: '1h' }
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
mockReq.headers!.authorization = `Bearer ${token}`;
|
|
454
|
-
|
|
455
|
-
const middleware = authenticateRequest({ loadFullUser: false });
|
|
456
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
457
|
-
|
|
458
|
-
expect(mockReq.userId).toBe('user123');
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
it('should extract token from cookies as fallback', async () => {
|
|
462
|
-
const token = jwt.sign(
|
|
463
|
-
{ id: 'user123', userId: 'user123', username: 'test' },
|
|
464
|
-
'test-secret',
|
|
465
|
-
{ expiresIn: '1h' }
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
mockReq.cookies!.accessToken = token;
|
|
469
|
-
|
|
470
|
-
const middleware = authenticateRequest({ loadFullUser: false });
|
|
471
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
472
|
-
|
|
473
|
-
expect(mockReq.userId).toBe('user123');
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
it('should handle malformed Authorization header', async () => {
|
|
477
|
-
mockReq.headers!.authorization = 'InvalidFormat token';
|
|
478
|
-
|
|
479
|
-
const middleware = authenticateRequest();
|
|
480
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
481
|
-
|
|
482
|
-
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
483
|
-
expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
484
|
-
error: 'MISSING_TOKEN'
|
|
485
|
-
}));
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
describe('error handling', () => {
|
|
490
|
-
it('should provide consistent error response format', async () => {
|
|
491
|
-
const middleware = authenticateRequest();
|
|
492
|
-
|
|
493
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
494
|
-
|
|
495
|
-
expect(mockRes.json).toHaveBeenCalledWith({
|
|
496
|
-
success: false,
|
|
497
|
-
error: 'MISSING_TOKEN',
|
|
498
|
-
message: 'Authentication required',
|
|
499
|
-
timestamp: expect.any(String)
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
it('should handle internal server errors gracefully', async () => {
|
|
504
|
-
// Force an internal error
|
|
505
|
-
const middleware = authenticateRequest();
|
|
506
|
-
|
|
507
|
-
// Mock internal error by making the middleware throw
|
|
508
|
-
mockReq.headers = undefined as any;
|
|
509
|
-
|
|
510
|
-
await middleware(mockReq as any, mockRes, mockNext);
|
|
511
|
-
|
|
512
|
-
expect(mockRes.status).toHaveBeenCalledWith(expect.any(Number));
|
|
513
|
-
expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
514
|
-
success: false
|
|
515
|
-
}));
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
describe('Integration Tests', () => {
|
|
521
|
-
describe('Frontend-Backend Authentication Flow', () => {
|
|
522
|
-
let authManager: AuthenticationManager;
|
|
523
|
-
|
|
524
|
-
beforeEach(() => {
|
|
525
|
-
authManager = new AuthenticationManager('http://localhost:3001');
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
it('should handle complete login flow', async () => {
|
|
529
|
-
const mockLoginResponse = {
|
|
530
|
-
data: {
|
|
531
|
-
success: true,
|
|
532
|
-
accessToken: 'mock-access-token',
|
|
533
|
-
refreshToken: 'mock-refresh-token',
|
|
534
|
-
user: { id: 'user123', username: 'testuser' }
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
mockAxiosInstance.post.mockResolvedValue(mockLoginResponse);
|
|
539
|
-
|
|
540
|
-
// Login
|
|
541
|
-
const result = await authManager.login({ username: 'test', password: 'pass' });
|
|
542
|
-
expect(result.success).toBe(true);
|
|
543
|
-
|
|
544
|
-
// Check auth state
|
|
545
|
-
const authState = authManager.getAuthState();
|
|
546
|
-
expect(authState.isAuthenticated).toBe(true);
|
|
547
|
-
expect(authState.user).toEqual(mockLoginResponse.data.user);
|
|
548
|
-
|
|
549
|
-
// Verify tokens are stored
|
|
550
|
-
expect(mockAsyncStorage.setItem).toHaveBeenCalledWith(
|
|
551
|
-
'@oxy/auth-tokens',
|
|
552
|
-
expect.stringContaining('mock-access-token')
|
|
553
|
-
);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
it('should handle authentication errors gracefully', async () => {
|
|
557
|
-
const errorResponse = {
|
|
558
|
-
response: {
|
|
559
|
-
status: 401,
|
|
560
|
-
data: { message: 'Invalid credentials' }
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
mockAxiosInstance.post.mockRejectedValue(errorResponse);
|
|
565
|
-
|
|
566
|
-
await expect(authManager.login({ username: 'test', password: 'wrong' }))
|
|
567
|
-
.rejects.toThrow('Invalid credentials');
|
|
568
|
-
|
|
569
|
-
const authState = authManager.getAuthState();
|
|
570
|
-
expect(authState.isAuthenticated).toBe(false);
|
|
571
|
-
});
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
describe('Token Lifecycle Management', () => {
|
|
575
|
-
it('should automatically refresh tokens before expiration', async () => {
|
|
576
|
-
const mockToken = jwt.sign(
|
|
577
|
-
{ id: 'user123', userId: 'user123' },
|
|
578
|
-
'test-secret',
|
|
579
|
-
{ expiresIn: '1m' } // Short expiry for testing
|
|
580
|
-
);
|
|
581
|
-
|
|
582
|
-
const authManager = new AuthenticationManager('http://localhost:3001');
|
|
583
|
-
|
|
584
|
-
// Set tokens
|
|
585
|
-
(authManager as any).tokens = {
|
|
586
|
-
accessToken: mockToken,
|
|
587
|
-
refreshToken: 'refresh-token'
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
// Mock refresh response
|
|
591
|
-
mockAxiosInstance.post.mockResolvedValue({
|
|
592
|
-
data: {
|
|
593
|
-
accessToken: 'new-access-token',
|
|
594
|
-
refreshToken: 'new-refresh-token'
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
// Simulate a request that should trigger refresh
|
|
599
|
-
await (authManager as any).ensureValidToken();
|
|
600
|
-
|
|
601
|
-
// Verify refresh was called
|
|
602
|
-
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/auth/refresh', {
|
|
603
|
-
refreshToken: 'refresh-token'
|
|
604
|
-
});
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
});
|