import { afterEach, beforeEach, expect, spyOn, it } from 'bun:test' import { DiscordClient } from '../client' import { DiscordCredentialManager } from '../credential-manager' import { DiscordTokenExtractor } from '../token-extractor' import { getNoDiscordTokenFoundMessage } from './auth' let extractorExtractSpy: ReturnType let clientTestAuthSpy: ReturnType let clientListServersSpy: ReturnType let credManagerLoadSpy: ReturnType let credManagerSaveSpy: ReturnType let credManagerClearTokenSpy: ReturnType beforeEach(() => { // Spy on DiscordTokenExtractor.prototype.extract extractorExtractSpy = spyOn(DiscordTokenExtractor.prototype, 'extract').mockResolvedValue([ { token: 'test-token-123', }, ]) // Spy on DiscordClient.prototype methods clientTestAuthSpy = spyOn(DiscordClient.prototype, 'testAuth').mockResolvedValue({ id: 'user-123', username: 'testuser', }) clientListServersSpy = spyOn(DiscordClient.prototype, 'listServers').mockResolvedValue([ { id: 'server-1', name: 'Server One' }, { id: 'server-2', name: 'Server Two' }, ]) // Spy on DiscordCredentialManager.prototype methods credManagerLoadSpy = spyOn(DiscordCredentialManager.prototype, 'load').mockResolvedValue({ token: null, current_server: null, servers: {}, }) credManagerSaveSpy = spyOn(DiscordCredentialManager.prototype, 'save').mockResolvedValue(undefined) credManagerClearTokenSpy = spyOn(DiscordCredentialManager.prototype, 'clearToken').mockResolvedValue(undefined) }) afterEach(() => { extractorExtractSpy?.mockRestore() clientTestAuthSpy?.mockRestore() clientListServersSpy?.mockRestore() credManagerLoadSpy?.mockRestore() credManagerSaveSpy?.mockRestore() credManagerClearTokenSpy?.mockRestore() }) it('extract: calls DiscordTokenExtractor', async () => { const extractor = new DiscordTokenExtractor() const result = await extractor.extract() expect(result).toBeDefined() expect(result[0]?.token).toBe('test-token-123') }) it('extract: validates token with DiscordClient', async () => { const client = await new DiscordClient().login({ token: 'test-token-123' }) const authInfo = await client.testAuth() expect(authInfo).toBeDefined() expect(authInfo.id).toBe('user-123') }) it('extract: discovers servers', async () => { const client = await new DiscordClient().login({ token: 'test-token-123' }) const servers = await client.listServers() expect(servers).toHaveLength(2) expect(servers[0].id).toBe('server-1') }) it('logout: clears credentials', async () => { const credManager = new DiscordCredentialManager() await credManager.clearToken() expect(credManager.clearToken).toHaveBeenCalled() }) it('status: returns auth state', async () => { const credManager = new DiscordCredentialManager() const config = await credManager.load() expect(config.token).toBeNull() expect(config.current_server).toBeNull() }) it('no-token message mentions desktop app and browser fallback', () => { expect(getNoDiscordTokenFoundMessage()).toContain('desktop app or a supported Chromium browser') })