import '@angular/compiler'; import { Injector, runInInjectionContext } from '@angular/core'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { of } from 'rxjs'; import { ServerDirectoryFacade } from '../../../server-directory'; import { SignalServerAuthService } from './signal-server-auth.service'; import { SignalServerAuthorizeService } from './signal-server-authorize.service'; const HOME_URL = 'https://signal.toju.app'; const FOREIGN_URL = 'https://signal-sweden.toju.app'; const homeUser = { id: 'user-1', username: 'alice', displayName: 'Alice', homeSignalServerUrl: HOME_URL }; describe('SignalServerAuthorizeService', () => { let router: { navigate: ReturnType; url: string }; let store: { select: ReturnType }; let serverDirectory: { ensureServerEndpoint: ReturnType; findServerByUrl: ReturnType; servers: ReturnType; testServer: ReturnType; }; let signalServerAuth: { ensureProvisioned: ReturnType; hasValidCredential: ReturnType; migrateHomeCredential: ReturnType; }; let service: SignalServerAuthorizeService; beforeEach(() => { router = { navigate: vi.fn(() => Promise.resolve(true)), url: '/room/room-1' }; store = { select: vi.fn(() => of(homeUser)) }; serverDirectory = { ensureServerEndpoint: vi.fn(() => ({ id: 'endpoint-1' })), findServerByUrl: vi.fn(() => ({ id: 'endpoint-1', status: 'online' })), servers: vi.fn(() => []), testServer: vi.fn(() => Promise.resolve()) }; signalServerAuth = { ensureProvisioned: vi.fn(() => Promise.resolve({ kind: 'skipped', reason: 'no-home-user' })), hasValidCredential: vi.fn(() => false), migrateHomeCredential: vi.fn() }; const injector = Injector.create({ providers: [ SignalServerAuthorizeService, { provide: Router, useValue: router }, { provide: Store, useValue: store }, { provide: ServerDirectoryFacade, useValue: serverDirectory }, { provide: SignalServerAuthService, useValue: signalServerAuth } ] }); service = runInInjectionContext(injector, () => injector.get(SignalServerAuthorizeService)); }); it('returns true immediately when a valid credential already exists', async () => { signalServerAuth.hasValidCredential.mockReturnValue(true); await expect(service.ensureCredentialForServerUrl(FOREIGN_URL)).resolves.toBe(true); expect(signalServerAuth.ensureProvisioned).not.toHaveBeenCalled(); }); it('never provisions or opens the authorize login page for the home signal server', async () => { await expect(service.ensureCredentialForServerUrl(HOME_URL)).resolves.toBe(false); expect(signalServerAuth.ensureProvisioned).not.toHaveBeenCalled(); expect(router.navigate).not.toHaveBeenCalled(); }); it('restores the home credential from the legacy token store instead of provisioning', async () => { signalServerAuth.hasValidCredential .mockReturnValueOnce(false) .mockReturnValue(true); await expect(service.ensureCredentialForServerUrl(HOME_URL)).resolves.toBe(true); expect(signalServerAuth.migrateHomeCredential).toHaveBeenCalledWith(homeUser); expect(signalServerAuth.ensureProvisioned).not.toHaveBeenCalled(); expect(router.navigate).not.toHaveBeenCalled(); }); it('treats scheme variants of the home url as the home server', async () => { await expect(service.ensureCredentialForServerUrl('wss://signal.toju.app/')).resolves.toBe(false); expect(signalServerAuth.ensureProvisioned).not.toHaveBeenCalled(); expect(router.navigate).not.toHaveBeenCalled(); }); it('keeps the home session active when automatic foreign provisioning cannot recover', async () => { await expect(service.ensureCredentialForServerUrl(FOREIGN_URL)).resolves.toBe(false); expect(signalServerAuth.ensureProvisioned).toHaveBeenCalledWith(FOREIGN_URL, homeUser); expect(router.navigate).not.toHaveBeenCalled(); }); it('returns true when foreign provisioning succeeds', async () => { signalServerAuth.ensureProvisioned.mockResolvedValue({ kind: 'provisioned', result: {} }); await expect(service.ensureCredentialForServerUrl(FOREIGN_URL)).resolves.toBe(true); expect(router.navigate).not.toHaveBeenCalled(); }); });