test(dashboard,frontend): add DashboardControllerTest, fix broken spec files and add login tests
- Add DashboardControllerTest with 4 tests for admin and user dashboard endpoints - Fix incorrect class name imports in header, admin-user-approval, metering-points, verify-email specs - Add missing ActivatedRoute/Router/AuthService providers in all spec files - Replace stub login spec with 10 comprehensive tests (form validation, role redirect, error handling) - Remove stale 'should render title' test from app.spec.ts
This commit is contained in:
parent
c180d6fd32
commit
0bfa0d98d5
@ -0,0 +1,77 @@
|
|||||||
|
package at.mueller.eeg.backend.dashboard.api;
|
||||||
|
|
||||||
|
import at.mueller.eeg.backend.dashboard.api.dto.DashboardStatsDto;
|
||||||
|
import at.mueller.eeg.backend.dashboard.service.DashboardService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class DashboardControllerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DashboardService dashboardService;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DashboardController dashboardController;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAdminDashboard() {
|
||||||
|
DashboardStatsDto.AdminStats stats = new DashboardStatsDto.AdminStats(5, 3, 12);
|
||||||
|
when(dashboardService.getAdminStats()).thenReturn(stats);
|
||||||
|
|
||||||
|
ResponseEntity<DashboardStatsDto.AdminStats> response = dashboardController.getAdminDashboard();
|
||||||
|
|
||||||
|
assertEquals(200, response.getStatusCode().value());
|
||||||
|
assertEquals(5, response.getBody().totalCommunities());
|
||||||
|
assertEquals(3, response.getBody().pendingUsers());
|
||||||
|
assertEquals(12, response.getBody().totalActiveMemberships());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAdminDashboard_empty() {
|
||||||
|
DashboardStatsDto.AdminStats stats = new DashboardStatsDto.AdminStats(0, 0, 0);
|
||||||
|
when(dashboardService.getAdminStats()).thenReturn(stats);
|
||||||
|
|
||||||
|
ResponseEntity<DashboardStatsDto.AdminStats> response = dashboardController.getAdminDashboard();
|
||||||
|
|
||||||
|
assertEquals(0, response.getBody().totalCommunities());
|
||||||
|
assertEquals(0, response.getBody().pendingUsers());
|
||||||
|
assertEquals(0, response.getBody().totalActiveMemberships());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getUserDashboard() {
|
||||||
|
UUID userId = UUID.randomUUID();
|
||||||
|
DashboardStatsDto.UserStats stats = new DashboardStatsDto.UserStats(3, 2, 1);
|
||||||
|
when(dashboardService.getUserStats(userId)).thenReturn(stats);
|
||||||
|
|
||||||
|
ResponseEntity<DashboardStatsDto.UserStats> response = dashboardController.getUserDashboard(userId.toString());
|
||||||
|
|
||||||
|
assertEquals(200, response.getStatusCode().value());
|
||||||
|
assertEquals(3, response.getBody().totalMeteringPoints());
|
||||||
|
assertEquals(2, response.getBody().activeMemberships());
|
||||||
|
assertEquals(1, response.getBody().pendingMemberships());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getUserDashboard_empty() {
|
||||||
|
UUID userId = UUID.randomUUID();
|
||||||
|
DashboardStatsDto.UserStats stats = new DashboardStatsDto.UserStats(0, 0, 0);
|
||||||
|
when(dashboardService.getUserStats(userId)).thenReturn(stats);
|
||||||
|
|
||||||
|
ResponseEntity<DashboardStatsDto.UserStats> response = dashboardController.getUserDashboard(userId.toString());
|
||||||
|
|
||||||
|
assertEquals(0, response.getBody().totalMeteringPoints());
|
||||||
|
assertEquals(0, response.getBody().activeMemberships());
|
||||||
|
assertEquals(0, response.getBody().pendingMemberships());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,15 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { App } from './app';
|
import { App } from './app';
|
||||||
|
|
||||||
describe('App', () => {
|
describe('App', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [App],
|
imports: [App],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } },
|
||||||
|
{ provide: Router, useValue: { events: { subscribe: () => {} }, navigate: () => {} } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -13,11 +18,4 @@ describe('App', () => {
|
|||||||
const app = fixture.componentInstance;
|
const app = fixture.componentInstance;
|
||||||
expect(app).toBeTruthy();
|
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('Hello, eeg_frontend');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
|
import {of} from 'rxjs';
|
||||||
import {DashboardLayout} from './dashboard-layout';
|
import {DashboardLayout} from './dashboard-layout';
|
||||||
|
import {AuthService} from '../../services/auth';
|
||||||
|
|
||||||
describe('DashboardLayout', () => {
|
describe('DashboardLayout', () => {
|
||||||
let component: DashboardLayout;
|
let component: DashboardLayout;
|
||||||
@ -9,6 +11,11 @@ describe('DashboardLayout', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [DashboardLayout],
|
imports: [DashboardLayout],
|
||||||
|
providers: [
|
||||||
|
{provide: ActivatedRoute, useValue: {snapshot: {queryParamMap: {get: () => null}}}},
|
||||||
|
{provide: Router, useValue: {events: of(), navigate: () => {}}},
|
||||||
|
{provide: AuthService, useValue: {currentUserRole: () => 'MEMBER', logout: () => {}}}
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(DashboardLayout);
|
fixture = TestBed.createComponent(DashboardLayout);
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Header } from './header';
|
import { HeaderComponent } from './header';
|
||||||
|
import { AuthService } from '../../services/auth';
|
||||||
|
|
||||||
describe('Header', () => {
|
describe('Header', () => {
|
||||||
let component: Header;
|
let component: HeaderComponent;
|
||||||
let fixture: ComponentFixture<Header>;
|
let fixture: ComponentFixture<HeaderComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [Header],
|
imports: [HeaderComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } },
|
||||||
|
{ provide: Router, useValue: { navigate: () => {} } },
|
||||||
|
{ provide: AuthService, useValue: { isLoggedIn: () => false, currentUserRole: () => null, logout: () => {} } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(Header);
|
fixture = TestBed.createComponent(HeaderComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { AdminUserApproval } from './admin-user-approval';
|
import { AdminUserApprovalComponent } from './admin-user-approval';
|
||||||
|
|
||||||
describe('AdminUserApproval', () => {
|
describe('AdminUserApproval', () => {
|
||||||
let component: AdminUserApproval;
|
let component: AdminUserApprovalComponent;
|
||||||
let fixture: ComponentFixture<AdminUserApproval>;
|
let fixture: ComponentFixture<AdminUserApprovalComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [AdminUserApproval],
|
imports: [AdminUserApprovalComponent],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(AdminUserApproval);
|
fixture = TestBed.createComponent(AdminUserApprovalComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { LandingPage } from './landing-page';
|
import { LandingPage } from './landing-page';
|
||||||
|
|
||||||
describe('LandingPage', () => {
|
describe('LandingPage', () => {
|
||||||
@ -9,6 +9,9 @@ describe('LandingPage', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [LandingPage],
|
imports: [LandingPage],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(LandingPage);
|
fixture = TestBed.createComponent(LandingPage);
|
||||||
|
|||||||
@ -1,22 +1,104 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { vi, expect, it, describe, beforeEach } from 'vitest';
|
||||||
|
import { of, throwError } from 'rxjs';
|
||||||
|
import { LoginComponent } from './login';
|
||||||
|
import { AuthService } from '../../services/auth';
|
||||||
|
|
||||||
import { Login } from './login';
|
describe('LoginComponent', () => {
|
||||||
|
let component: LoginComponent;
|
||||||
describe('Login', () => {
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
let component: Login;
|
let authService: { login: ReturnType<typeof vi.fn> };
|
||||||
let fixture: ComponentFixture<Login>;
|
let router: { navigate: ReturnType<typeof vi.fn> };
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
authService = { login: vi.fn() };
|
||||||
|
router = { navigate: vi.fn() };
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [Login],
|
imports: [LoginComponent, ReactiveFormsModule],
|
||||||
|
providers: [
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
|
{ provide: Router, useValue: router },
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(Login);
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should have invalid form when empty', () => {
|
||||||
|
expect(component.loginForm.valid).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have valid form when email and password are filled', () => {
|
||||||
|
component.loginForm.setValue({ email: 'test@example.at', password: 'password123' });
|
||||||
|
expect(component.loginForm.valid).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call login when form is invalid', () => {
|
||||||
|
component.onSubmit();
|
||||||
|
expect(authService.login).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call login and redirect to /dashboard for ADMIN role', () => {
|
||||||
|
authService.login.mockReturnValue(of({ token: 'abc', role: 'ADMIN' }));
|
||||||
|
component.loginForm.setValue({ email: 'admin@example.at', password: 'password123' });
|
||||||
|
|
||||||
|
component.onSubmit();
|
||||||
|
|
||||||
|
expect(authService.login).toHaveBeenCalledWith({ email: 'admin@example.at', password: 'password123' });
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/dashboard']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call login and redirect to /dashboard for MEMBER role', () => {
|
||||||
|
authService.login.mockReturnValue(of({ token: 'abc', role: 'MEMBER' }));
|
||||||
|
component.loginForm.setValue({ email: 'member@example.at', password: 'password123' });
|
||||||
|
|
||||||
|
component.onSubmit();
|
||||||
|
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/dashboard']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect to / for unknown role', () => {
|
||||||
|
authService.login.mockReturnValue(of({ token: 'abc', role: 'GUEST' }));
|
||||||
|
component.loginForm.setValue({ email: 'guest@example.at', password: 'password123' });
|
||||||
|
|
||||||
|
component.onSubmit();
|
||||||
|
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display error message on login failure', () => {
|
||||||
|
authService.login.mockReturnValue(throwError(() => ({
|
||||||
|
error: { message: 'Ungültige Anmeldedaten' }
|
||||||
|
})));
|
||||||
|
component.loginForm.setValue({ email: 'test@example.at', password: 'wrong' });
|
||||||
|
|
||||||
|
component.onSubmit();
|
||||||
|
|
||||||
|
expect(component.errorMessage).toBe('Ungültige Anmeldedaten');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display generic error when server returns no message', () => {
|
||||||
|
authService.login.mockReturnValue(throwError(() => ({ error: {} })));
|
||||||
|
component.loginForm.setValue({ email: 'test@example.at', password: 'wrong' });
|
||||||
|
|
||||||
|
component.onSubmit();
|
||||||
|
|
||||||
|
expect(component.errorMessage).toBe('Ein unbekannter Fehler ist aufgetreten.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have disabled submit button when form is invalid', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const button = fixture.nativeElement.querySelector('button[type="submit"]');
|
||||||
|
expect(button.disabled).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { MeteringPoints } from './metering-points';
|
import { MeteringPointsComponent } from './metering-points';
|
||||||
|
|
||||||
describe('MeteringPoints', () => {
|
describe('MeteringPoints', () => {
|
||||||
let component: MeteringPoints;
|
let component: MeteringPointsComponent;
|
||||||
let fixture: ComponentFixture<MeteringPoints>;
|
let fixture: ComponentFixture<MeteringPointsComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [MeteringPoints],
|
imports: [MeteringPointsComponent],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(MeteringPoints);
|
fixture = TestBed.createComponent(MeteringPointsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Register } from './register';
|
import { Register } from './register';
|
||||||
|
|
||||||
describe('Register', () => {
|
describe('Register', () => {
|
||||||
@ -9,6 +9,9 @@ describe('Register', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [Register],
|
imports: [Register],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(Register);
|
fixture = TestBed.createComponent(Register);
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { VerifyEmail } from './verify-email';
|
import { VerifyEmailComponent } from './verify-email';
|
||||||
|
|
||||||
describe('VerifyEmail', () => {
|
describe('VerifyEmail', () => {
|
||||||
let component: VerifyEmail;
|
let component: VerifyEmailComponent;
|
||||||
let fixture: ComponentFixture<VerifyEmail>;
|
let fixture: ComponentFixture<VerifyEmailComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [VerifyEmail],
|
imports: [VerifyEmailComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(VerifyEmail);
|
fixture = TestBed.createComponent(VerifyEmailComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user