WIP: A simple cli for daily tangled use cases and AI integration. This is for my personal use right now, but happy if others get mileage from it! :)
at pull-request-format-testing 143 lines 4.4 kB view raw
1import type { AtpSessionData } from '@atproto/api'; 2import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; 3import { 4 clearCurrentSessionMetadata, 5 deleteSession, 6 getCurrentSessionMetadata, 7 loadSession, 8 saveCurrentSessionMetadata, 9 saveSession, 10} from '../../src/lib/session.js'; 11import { mockSessionData, mockSessionData2, mockSessionMetadata } from '../helpers/mock-data.js'; 12 13// Mock @napi-rs/keyring 14const mockKeyringStorage = new Map<string, string>(); 15 16vi.mock('@napi-rs/keyring', () => { 17 return { 18 AsyncEntry: vi.fn().mockImplementation((service: string, account: string) => { 19 const key = `${service}:${account}`; 20 21 return { 22 setPassword: vi.fn().mockImplementation(async (password: string) => { 23 mockKeyringStorage.set(key, password); 24 }), 25 getPassword: vi.fn().mockImplementation(async () => { 26 return mockKeyringStorage.get(key) || null; 27 }), 28 deleteCredential: vi.fn().mockImplementation(async () => { 29 return mockKeyringStorage.delete(key); 30 }), 31 }; 32 }), 33 }; 34}); 35 36describe('Session Management', () => { 37 beforeEach(() => { 38 // Clear mock storage before each test 39 mockKeyringStorage.clear(); 40 vi.clearAllMocks(); 41 }); 42 43 afterEach(() => { 44 // Clean up after each test 45 mockKeyringStorage.clear(); 46 }); 47 48 describe('saveSession', () => { 49 it('should save session to keychain using DID', async () => { 50 await saveSession(mockSessionData); 51 52 // Verify session was stored 53 const loaded = await loadSession(mockSessionData.did); 54 expect(loaded).toEqual(mockSessionData); 55 }); 56 57 it('should save and retrieve session with all required fields', async () => { 58 await saveSession(mockSessionData2); 59 60 // Verify session was stored (keyed by DID) 61 const loaded = await loadSession(mockSessionData2.did); 62 expect(loaded).toEqual(mockSessionData2); 63 }); 64 65 it('should throw error if session has no DID or handle', async () => { 66 const sessionData = { 67 email: 'user@example.com', 68 accessJwt: 'token123', 69 refreshJwt: 'refresh123', 70 } as AtpSessionData; 71 72 await expect(saveSession(sessionData)).rejects.toThrow( 73 'Session data must include DID or handle' 74 ); 75 }); 76 }); 77 78 describe('loadSession', () => { 79 it('should load session from keychain', async () => { 80 await saveSession(mockSessionData); 81 const result = await loadSession(mockSessionData.did); 82 83 expect(result).toEqual(mockSessionData); 84 }); 85 86 it('should return null when session not found', async () => { 87 const result = await loadSession('did:plc:notfound'); 88 expect(result).toBeNull(); 89 }); 90 }); 91 92 describe('deleteSession', () => { 93 it('should delete session from keychain', async () => { 94 await saveSession(mockSessionData); 95 96 // Verify session exists 97 let loaded = await loadSession(mockSessionData.did); 98 expect(loaded).toEqual(mockSessionData); 99 100 // Delete session 101 const deleted = await deleteSession(mockSessionData.did); 102 expect(deleted).toBe(true); 103 104 // Verify session no longer exists 105 loaded = await loadSession(mockSessionData.did); 106 expect(loaded).toBeNull(); 107 }); 108 109 it('should return false when deleting non-existent session', async () => { 110 const deleted = await deleteSession('did:plc:notfound'); 111 expect(deleted).toBe(false); 112 }); 113 }); 114 115 describe('session metadata', () => { 116 it('should save and load current session metadata', async () => { 117 await saveCurrentSessionMetadata(mockSessionMetadata); 118 const result = await getCurrentSessionMetadata(); 119 120 expect(result).toEqual(mockSessionMetadata); 121 }); 122 123 it('should return null when no metadata exists', async () => { 124 const result = await getCurrentSessionMetadata(); 125 expect(result).toBeNull(); 126 }); 127 128 it('should clear current session metadata', async () => { 129 await saveCurrentSessionMetadata(mockSessionMetadata); 130 131 // Verify metadata exists 132 let result = await getCurrentSessionMetadata(); 133 expect(result).toEqual(mockSessionMetadata); 134 135 // Clear metadata 136 await clearCurrentSessionMetadata(); 137 138 // Verify metadata no longer exists 139 result = await getCurrentSessionMetadata(); 140 expect(result).toBeNull(); 141 }); 142 }); 143});