update test
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import { vi } from 'vitest';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { authGuard } from './auth.guard';
|
||||
import { KeycloakService } from './keycloak.service';
|
||||
|
||||
describe('authGuard', () => {
|
||||
let mockKeycloak: { isLoggedIn: ReturnType<typeof vi.fn>; login: ReturnType<typeof vi.fn> };
|
||||
|
||||
beforeEach(() => {
|
||||
mockKeycloak = {
|
||||
isLoggedIn: vi.fn().mockReturnValue(true),
|
||||
login: vi.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{ provide: KeycloakService, useValue: mockKeycloak }],
|
||||
});
|
||||
});
|
||||
|
||||
const runGuard = () =>
|
||||
TestBed.runInInjectionContext(() =>
|
||||
authGuard({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot),
|
||||
);
|
||||
|
||||
it('returns true when the user is logged in', () => {
|
||||
mockKeycloak.isLoggedIn.mockReturnValue(true);
|
||||
expect(runGuard()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when the user is not logged in', () => {
|
||||
mockKeycloak.isLoggedIn.mockReturnValue(false);
|
||||
expect(runGuard()).toBe(false);
|
||||
});
|
||||
|
||||
it('calls login() when the user is not logged in', () => {
|
||||
mockKeycloak.isLoggedIn.mockReturnValue(false);
|
||||
runGuard();
|
||||
expect(mockKeycloak.login).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not call login() when the user is already logged in', () => {
|
||||
mockKeycloak.isLoggedIn.mockReturnValue(true);
|
||||
runGuard();
|
||||
expect(mockKeycloak.login).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { vi } from 'vitest';
|
||||
import { HttpRequest } from '@angular/common/http';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { firstValueFrom, of } from 'rxjs';
|
||||
import { authInterceptor } from './auth.interceptor';
|
||||
import { KeycloakService } from './keycloak.service';
|
||||
import { API_BASE_URL } from '../issues/issues-api.service';
|
||||
|
||||
describe('authInterceptor', () => {
|
||||
let mockKeycloak: { getToken: ReturnType<typeof vi.fn> };
|
||||
|
||||
beforeEach(() => {
|
||||
mockKeycloak = { getToken: vi.fn().mockResolvedValue('test-token') };
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{ provide: KeycloakService, useValue: mockKeycloak }],
|
||||
});
|
||||
});
|
||||
|
||||
const intercept = (req: HttpRequest<unknown>) => {
|
||||
const captured: HttpRequest<unknown>[] = [];
|
||||
const next = vi.fn((r: HttpRequest<unknown>) => { captured.push(r); return of(null as any); });
|
||||
const obs = TestBed.runInInjectionContext(() => authInterceptor(req, next as any));
|
||||
return { obs, next, captured };
|
||||
};
|
||||
|
||||
it('skips token logic for requests outside API_BASE_URL', () => {
|
||||
const req = new HttpRequest('GET', 'http://other.example.com/data');
|
||||
const { next } = intercept(req);
|
||||
expect(mockKeycloak.getToken).not.toHaveBeenCalled();
|
||||
expect(next).toHaveBeenCalledWith(req);
|
||||
});
|
||||
|
||||
it('calls getToken for requests to API_BASE_URL', () => {
|
||||
const req = new HttpRequest('GET', `${API_BASE_URL}/issues`);
|
||||
intercept(req);
|
||||
expect(mockKeycloak.getToken).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds Authorization header when token is available', async () => {
|
||||
mockKeycloak.getToken.mockResolvedValue('my-token');
|
||||
const req = new HttpRequest('GET', `${API_BASE_URL}/issues`);
|
||||
const { obs, captured } = intercept(req);
|
||||
await firstValueFrom(obs);
|
||||
expect(captured[0].headers.get('Authorization')).toBe('Bearer my-token');
|
||||
});
|
||||
|
||||
it('forwards the request without Authorization header when token is undefined', async () => {
|
||||
mockKeycloak.getToken.mockResolvedValue(undefined);
|
||||
const req = new HttpRequest('GET', `${API_BASE_URL}/issues`);
|
||||
const { obs, captured } = intercept(req);
|
||||
await firstValueFrom(obs);
|
||||
expect(captured[0].headers.has('Authorization')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
import { vi } from 'vitest';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { KeycloakService } from './keycloak.service';
|
||||
|
||||
const mockKc = vi.hoisted(() => ({
|
||||
init: vi.fn(),
|
||||
login: vi.fn(),
|
||||
logout: vi.fn(),
|
||||
updateToken: vi.fn(),
|
||||
token: 'mock-token' as string | undefined,
|
||||
tokenParsed: { preferred_username: 'testuser' } as Record<string, string> | undefined,
|
||||
authenticated: true as boolean | undefined,
|
||||
onTokenExpired: undefined as (() => void) | undefined,
|
||||
}));
|
||||
|
||||
vi.mock('keycloak-js', () => ({ default: vi.fn(function () { return mockKc; }) }));
|
||||
|
||||
describe('KeycloakService', () => {
|
||||
let service: KeycloakService;
|
||||
|
||||
beforeEach(() => {
|
||||
mockKc.init.mockResolvedValue(true);
|
||||
mockKc.login.mockResolvedValue(undefined);
|
||||
mockKc.logout.mockResolvedValue(undefined);
|
||||
mockKc.updateToken.mockResolvedValue(true);
|
||||
mockKc.token = 'mock-token';
|
||||
mockKc.tokenParsed = { preferred_username: 'testuser' };
|
||||
mockKc.authenticated = true;
|
||||
mockKc.onTokenExpired = undefined;
|
||||
|
||||
vi.clearAllMocks();
|
||||
mockKc.init.mockResolvedValue(true);
|
||||
mockKc.login.mockResolvedValue(undefined);
|
||||
mockKc.logout.mockResolvedValue(undefined);
|
||||
mockKc.updateToken.mockResolvedValue(true);
|
||||
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(KeycloakService);
|
||||
});
|
||||
|
||||
describe('init', () => {
|
||||
it('sets isAuthenticated to true when authenticated', async () => {
|
||||
await service.init();
|
||||
expect(service.isAuthenticated()).toBe(true);
|
||||
});
|
||||
|
||||
it('sets username from tokenParsed when authenticated', async () => {
|
||||
await service.init();
|
||||
expect(service.username()).toBe('testuser');
|
||||
});
|
||||
|
||||
it('registers an onTokenExpired handler when authenticated', async () => {
|
||||
await service.init();
|
||||
expect(mockKc.onTokenExpired).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
it('onTokenExpired calls logout when updateToken fails', async () => {
|
||||
mockKc.updateToken.mockRejectedValue(new Error('expired'));
|
||||
await service.init();
|
||||
await mockKc.onTokenExpired!();
|
||||
expect(mockKc.logout).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sets isAuthenticated to false when not authenticated', async () => {
|
||||
mockKc.init.mockResolvedValue(false);
|
||||
await service.init();
|
||||
expect(service.isAuthenticated()).toBe(false);
|
||||
});
|
||||
|
||||
it('leaves username undefined when not authenticated', async () => {
|
||||
mockKc.init.mockResolvedValue(false);
|
||||
await service.init();
|
||||
expect(service.username()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('handles init failure gracefully without throwing', async () => {
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mockKc.init.mockRejectedValue(new Error('connection refused'));
|
||||
await expect(service.init()).resolves.toBeUndefined();
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it('logs an error when init throws', async () => {
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mockKc.init.mockRejectedValue(new Error('fail'));
|
||||
await service.init();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
it('delegates to keycloak.login()', async () => {
|
||||
await service.login();
|
||||
expect(mockKc.login).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout', () => {
|
||||
it('delegates to keycloak.logout() with window.location.origin as redirectUri', async () => {
|
||||
await service.logout();
|
||||
expect(mockKc.logout).toHaveBeenCalledWith({ redirectUri: window.location.origin });
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLoggedIn', () => {
|
||||
it('returns true when keycloak.authenticated is true', () => {
|
||||
mockKc.authenticated = true;
|
||||
expect(service.isLoggedIn()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when keycloak.authenticated is false', () => {
|
||||
mockKc.authenticated = false;
|
||||
expect(service.isLoggedIn()).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when keycloak.authenticated is undefined', () => {
|
||||
mockKc.authenticated = undefined;
|
||||
expect(service.isLoggedIn()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken', () => {
|
||||
it('calls updateToken(30) and returns the token', async () => {
|
||||
mockKc.token = 'fresh-token';
|
||||
const token = await service.getToken();
|
||||
expect(mockKc.updateToken).toHaveBeenCalledWith(30);
|
||||
expect(token).toBe('fresh-token');
|
||||
});
|
||||
|
||||
it('returns undefined when updateToken fails', async () => {
|
||||
mockKc.updateToken.mockRejectedValue(new Error('session expired'));
|
||||
const token = await service.getToken();
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user