Files
Toju/toju-app/src/app/domains/authentication/application/services/signal-server-authorize.service.spec.ts
T
myxeliumandCursor d3d22846e7 fix: Bug - User login status showing as both logged in and logged out
Stop treating transient auth_required as home-session expiry, keep auth scope
consistent across login redirect and server-rail joins, and leave /login when
the in-memory user is still authenticated.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 01:54:01 +02:00

121 lines
4.5 KiB
TypeScript

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<typeof vi.fn>; url: string };
let store: { select: ReturnType<typeof vi.fn> };
let serverDirectory: {
ensureServerEndpoint: ReturnType<typeof vi.fn>;
findServerByUrl: ReturnType<typeof vi.fn>;
servers: ReturnType<typeof vi.fn>;
testServer: ReturnType<typeof vi.fn>;
};
let signalServerAuth: {
ensureProvisioned: ReturnType<typeof vi.fn>;
hasValidCredential: ReturnType<typeof vi.fn>;
migrateHomeCredential: ReturnType<typeof vi.fn>;
};
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-provision-secret' })),
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('still provisions foreign servers and navigates to authorize when the secret is missing', async () => {
await expect(service.ensureCredentialForServerUrl(FOREIGN_URL)).resolves.toBe(false);
expect(signalServerAuth.ensureProvisioned).toHaveBeenCalledWith(FOREIGN_URL, homeUser);
expect(router.navigate).toHaveBeenCalledWith(['/login'], expect.objectContaining({
queryParams: expect.objectContaining({ mode: 'authorize' })
}));
});
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();
});
});