import { TestBed } from '@angular/core/testing'; import { App } from './app'; import { OAuthService } from 'angular-oauth2-oidc'; import { HttpClient } from '@angular/common/http'; import { of, throwError } from 'rxjs'; import { vi } from 'vitest'; describe('App', () => { let mockOAuthService: any; let mockHttpClient: any; beforeEach(async () => { mockOAuthService = { hasValidAccessToken: () => false, getIdentityClaims: () => null, getAccessToken: () => 'mock-token', initCodeFlow: vi.fn(), revokeTokenAndLogout: vi.fn() }; mockHttpClient = { get: () => of('Hello from mocked API!') }; await TestBed.configureTestingModule({ imports: [App], providers: [ { provide: OAuthService, useValue: mockOAuthService }, { provide: HttpClient, useValue: mockHttpClient } ] }).compileComponents(); }); it('should create the app', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; expect(app).toBeTruthy(); }); it('should render title', async () => { const fixture = TestBed.createComponent(App); await fixture.whenStable(); const compiled = fixture.nativeElement as HTMLElement; expect(compiled.querySelector('h1')?.textContent).toContain('LMNP Organizer'); }); it('should return login status based on OAuthService', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; mockOAuthService.hasValidAccessToken = () => true; expect(app.isLoggedIn).toBe(true); mockOAuthService.hasValidAccessToken = () => false; expect(app.isLoggedIn).toBe(false); }); it('should return username and email from identity claims', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; // Default username when no claims expect(app.username).toBe(''); // Custom claims mockOAuthService.getIdentityClaims = () => ({ preferred_username: 'Alice', email: 'alice@example.com' }); expect(app.username).toBe('Alice'); expect(app.email).toBe('alice@example.com'); }); it('should invoke OIDC login and logout flows', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; const loginSpy = vi.spyOn(mockOAuthService, 'initCodeFlow'); const logoutSpy = vi.spyOn(mockOAuthService, 'revokeTokenAndLogout'); app.login(); expect(loginSpy).toHaveBeenCalled(); app.logout(); expect(logoutSpy).toHaveBeenCalled(); }); it('should call hello API and set message on success', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; app.callHelloApi(); expect(app.helloMessage()).toBe('Hello from mocked API!'); }); it('should call hello API and handle error', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; mockHttpClient.get = () => throwError(() => ({ statusText: 'Unauthorized' })); app.callHelloApi(); expect(app.helloMessage()).toBe('Failed to connect to backend: Unauthorized'); }); it('should render logged in state when user is authenticated', async () => { const fixture = TestBed.createComponent(App); // Log in mockOAuthService.hasValidAccessToken = () => true; mockOAuthService.getIdentityClaims = () => ({ preferred_username: 'Alice', email: 'alice@example.com' }); fixture.detectChanges(); await fixture.whenStable(); const compiled = fixture.nativeElement as HTMLElement; expect(compiled.querySelector('.user-details h3')?.textContent).toContain('Alice'); expect(compiled.querySelector('.user-email')?.textContent).toContain('alice@example.com'); }); it('should render hello API response when API button is clicked', async () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; // Log in mockOAuthService.hasValidAccessToken = () => true; mockOAuthService.getIdentityClaims = () => ({ preferred_username: 'Alice', email: 'alice@example.com' }); fixture.detectChanges(); await fixture.whenStable(); // Click button const compiled = fixture.nativeElement as HTMLElement; const button = compiled.querySelector('.api-actions button') as HTMLButtonElement; button.click(); fixture.detectChanges(); await fixture.whenStable(); // Verify response message is shown expect(app.helloMessage()).toBe('Hello from mocked API!'); fixture.detectChanges(); expect(compiled.querySelector('.api-response-code')?.textContent).toContain('Hello from mocked API!'); }); });