The generated API service requires userId as a second parameter for deleteUserTariff(). Inject AuthService and use getCurrentUserId() to provide the required argument, unblocking the entire frontend test suite.
455 lines
17 KiB
TypeScript
455 lines
17 KiB
TypeScript
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
import { provideHttpClient } from '@angular/common/http';
|
|
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
|
import { vi } from 'vitest';
|
|
import { AdminUserApprovalComponent } from './admin-user-approval';
|
|
import { UserProfileResponse } from '../../api';
|
|
|
|
describe('AdminUserApprovalComponent', () => {
|
|
let component: AdminUserApprovalComponent;
|
|
let fixture: ComponentFixture<AdminUserApprovalComponent>;
|
|
let httpMock: HttpTestingController;
|
|
|
|
const mockPendingUser: UserProfileResponse = {
|
|
id: '1',
|
|
firstName: 'Max',
|
|
lastName: 'Mustermann',
|
|
email: 'max@test.at',
|
|
status: 'PENDING',
|
|
participantType: UserProfileResponse.ParticipantTypeEnum.Private,
|
|
};
|
|
|
|
const mockApprovedUser: UserProfileResponse = {
|
|
id: '2',
|
|
firstName: 'Anna',
|
|
lastName: 'Schmidt',
|
|
email: 'anna@test.at',
|
|
status: 'APPROVED',
|
|
participantType: UserProfileResponse.ParticipantTypeEnum.Company,
|
|
};
|
|
|
|
const mockRejectedUser: UserProfileResponse = {
|
|
id: '3',
|
|
firstName: 'Tom',
|
|
lastName: 'Berger',
|
|
email: 'tom@test.at',
|
|
status: 'REJECTED',
|
|
participantType: UserProfileResponse.ParticipantTypeEnum.Private,
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
await TestBed.configureTestingModule({
|
|
imports: [AdminUserApprovalComponent],
|
|
providers: [provideHttpClient(), provideHttpClientTesting()],
|
|
}).compileComponents();
|
|
|
|
fixture = TestBed.createComponent(AdminUserApprovalComponent);
|
|
component = fixture.componentInstance;
|
|
httpMock = TestBed.inject(HttpTestingController);
|
|
});
|
|
|
|
afterEach(() => {
|
|
httpMock.verify();
|
|
});
|
|
|
|
it('should create', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
expect(component).toBeTruthy();
|
|
});
|
|
|
|
it('should default activeTab to pending', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
expect(component.activeTab()).toBe('pending');
|
|
});
|
|
|
|
it('should initialize allUsers as empty array', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
expect(component.allUsers()).toEqual([]);
|
|
});
|
|
|
|
it('should load pending users on init', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
expect(req.request.method).toBe('GET');
|
|
req.flush([mockPendingUser]);
|
|
expect(component.pendingUsers().length).toBe(1);
|
|
expect(component.pendingUsers()[0].firstName).toBe('Max');
|
|
});
|
|
|
|
it('should load all users via getAllUsers endpoint when switching to all tab', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
expect(allReq.request.method).toBe('GET');
|
|
allReq.flush([mockPendingUser, mockApprovedUser, mockRejectedUser]);
|
|
|
|
expect(component.allUsers().length).toBe(3);
|
|
});
|
|
|
|
it('should switch activeTab signal', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([]);
|
|
expect(component.activeTab()).toBe('all');
|
|
|
|
component.switchTab('pending');
|
|
expect(component.activeTab()).toBe('pending');
|
|
});
|
|
|
|
it('should not reload all users if already loaded', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockApprovedUser]);
|
|
fixture.detectChanges();
|
|
|
|
component.switchTab('pending');
|
|
expect(component.activeTab()).toBe('pending');
|
|
|
|
component.switchTab('all');
|
|
expect(component.activeTab()).toBe('all');
|
|
const allReqs = httpMock.match((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
expect(allReqs.length).toBe(0);
|
|
});
|
|
|
|
it('should set error message when loadPendingUsers fails', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush('Error', { status: 500, statusText: 'Server Error' });
|
|
|
|
expect(component.errorMessage()).toBe(
|
|
'Fehler beim Laden der Daten aus dem EDA-Netz-Check.',
|
|
);
|
|
expect(component.isLoading()).toBe(false);
|
|
});
|
|
|
|
it('should set error message when loadAllUsers fails', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush('Error', { status: 500, statusText: 'Server Error' });
|
|
|
|
expect(component.errorMessage()).toBe('Fehler beim Laden aller Benutzer.');
|
|
expect(component.isLoading()).toBe(false);
|
|
});
|
|
|
|
describe('getStatusLabel', () => {
|
|
it('should return "Ausstehend" for PENDING', () => {
|
|
expect(component.getStatusLabel('PENDING')).toBe('Ausstehend');
|
|
});
|
|
|
|
it('should return "Aktiv" for ACTIVE', () => {
|
|
expect(component.getStatusLabel('ACTIVE')).toBe('Aktiv');
|
|
});
|
|
|
|
it('should return "Freigeschaltet" for APPROVED', () => {
|
|
expect(component.getStatusLabel('APPROVED')).toBe('Freigeschaltet');
|
|
});
|
|
|
|
it('should return "Inaktiv" for INACTIVE', () => {
|
|
expect(component.getStatusLabel('INACTIVE')).toBe('Inaktiv');
|
|
});
|
|
|
|
it('should return "Abgelehnt" for REJECTED', () => {
|
|
expect(component.getStatusLabel('REJECTED')).toBe('Abgelehnt');
|
|
});
|
|
|
|
it('should return the original status for unknown values', () => {
|
|
expect(component.getStatusLabel('UNKNOWN')).toBe('UNKNOWN');
|
|
});
|
|
});
|
|
|
|
describe('getStatusBadgeClass', () => {
|
|
it('should return yellow badge for PENDING', () => {
|
|
expect(component.getStatusBadgeClass('PENDING')).toContain('yellow');
|
|
});
|
|
|
|
it('should return green badge for APPROVED', () => {
|
|
expect(component.getStatusBadgeClass('APPROVED')).toContain('green');
|
|
});
|
|
|
|
it('should return green badge for ACTIVE', () => {
|
|
expect(component.getStatusBadgeClass('ACTIVE')).toContain('green');
|
|
});
|
|
|
|
it('should return red badge for REJECTED', () => {
|
|
expect(component.getStatusBadgeClass('REJECTED')).toContain('red');
|
|
});
|
|
|
|
it('should return red badge for INACTIVE', () => {
|
|
expect(component.getStatusBadgeClass('INACTIVE')).toContain('red');
|
|
});
|
|
});
|
|
|
|
it('should approve user and remove from pending list', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([mockPendingUser]);
|
|
|
|
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
component.approveUser(mockPendingUser.id);
|
|
|
|
const approveReq = httpMock.expectOne((r) => r.url.includes('/approve'));
|
|
approveReq.flush({});
|
|
expect(component.pendingUsers().length).toBe(0);
|
|
});
|
|
|
|
it('should not call API when approveUser has undefined userId', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.approveUser(undefined);
|
|
|
|
const approveReqs = httpMock.match((r) => r.url.includes('/approve'));
|
|
expect(approveReqs.length).toBe(0);
|
|
});
|
|
|
|
it('should reject user and remove from pending list', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([mockPendingUser]);
|
|
|
|
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
component.rejectUser(mockPendingUser);
|
|
|
|
const rejectReq = httpMock.expectOne((r) => r.url.includes('/reject'));
|
|
rejectReq.flush({});
|
|
expect(component.pendingUsers().length).toBe(0);
|
|
});
|
|
|
|
it('should not call API when rejectUser has undefined id', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.rejectUser({ ...mockPendingUser, id: undefined });
|
|
|
|
const rejectReqs = httpMock.match((r) => r.url.includes('/reject'));
|
|
expect(rejectReqs.length).toBe(0);
|
|
});
|
|
|
|
it('should show error message when approveUser fails', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([mockPendingUser]);
|
|
|
|
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
component.approveUser(mockPendingUser.id);
|
|
|
|
const approveReq = httpMock.expectOne((r) => r.url.includes('/approve'));
|
|
approveReq.flush('Error', { status: 500, statusText: 'Server Error' });
|
|
|
|
expect(component.errorMessage()).toBe('Der User konnte nicht freigegeben werden.');
|
|
});
|
|
|
|
it('should show error toast when rejectUser fails', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([mockPendingUser]);
|
|
|
|
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
component.rejectUser(mockPendingUser);
|
|
|
|
const rejectReq = httpMock.expectOne((r) => r.url.includes('/reject'));
|
|
rejectReq.flush({ message: 'Ablehnung fehlgeschlagen' }, { status: 500, statusText: 'Server Error' });
|
|
});
|
|
|
|
describe('template', () => {
|
|
it('should render tab navigation with two tabs', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
fixture.detectChanges();
|
|
|
|
const tabs = fixture.nativeElement.querySelectorAll('[role="tab"]');
|
|
expect(tabs.length).toBe(2);
|
|
expect(tabs[0].textContent).toContain('Ausstehende Anträge');
|
|
expect(tabs[1].textContent).toContain('Alle Benutzer');
|
|
});
|
|
|
|
it('should show pending tab as active by default', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
fixture.detectChanges();
|
|
|
|
const activeTab = fixture.nativeElement.querySelector('[role="tab"][aria-selected="true"]');
|
|
expect(activeTab?.textContent).toContain('Ausstehende Anträge');
|
|
});
|
|
|
|
it('should show only one Status column header in pending tab (no duplicate)', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([mockPendingUser]);
|
|
fixture.detectChanges();
|
|
|
|
const allHeaders = fixture.nativeElement.querySelectorAll('th');
|
|
let statusCount = 0;
|
|
for (let i = 0; i < allHeaders.length; i++) {
|
|
if (allHeaders[i].textContent?.trim() === 'Status') {
|
|
statusCount++;
|
|
}
|
|
}
|
|
expect(statusCount).toBe(1);
|
|
});
|
|
|
|
it('should show pending users table with Freigeben and Ablehnen buttons', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([mockPendingUser]);
|
|
fixture.detectChanges();
|
|
|
|
const table = fixture.nativeElement.querySelector('table');
|
|
expect(table).toBeTruthy();
|
|
const rows = fixture.nativeElement.querySelectorAll('tbody tr');
|
|
expect(rows.length).toBe(1);
|
|
|
|
const buttons = rows[0].querySelectorAll('button');
|
|
expect(buttons.length).toBe(2);
|
|
expect(buttons[0].textContent?.trim()).toBe('Freigeben');
|
|
expect(buttons[1].textContent?.trim()).toBe('Ablehnen');
|
|
});
|
|
|
|
it('should show empty state message when no pending users', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([]);
|
|
fixture.detectChanges();
|
|
|
|
const emptyMsg = fixture.nativeElement.querySelector('.bg-gray-50 p');
|
|
expect(emptyMsg?.textContent).toContain(
|
|
'Aktuell gibt es keine neuen User im Status PENDING',
|
|
);
|
|
});
|
|
|
|
it('should show all users table without action buttons', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockApprovedUser]);
|
|
fixture.detectChanges();
|
|
|
|
const table = fixture.nativeElement.querySelector('table');
|
|
expect(table).toBeTruthy();
|
|
const rows = fixture.nativeElement.querySelectorAll('tbody tr');
|
|
expect(rows.length).toBe(1);
|
|
|
|
const buttons = rows[0].querySelectorAll('button');
|
|
expect(buttons.length).toBe(0);
|
|
});
|
|
|
|
it('should show empty state when no users exist', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([]);
|
|
fixture.detectChanges();
|
|
|
|
const emptyMsg = fixture.nativeElement.querySelector('.bg-gray-50 p');
|
|
expect(emptyMsg?.textContent).toContain('Keine Benutzer vorhanden');
|
|
});
|
|
|
|
it('should display role as Unternehmen for Company participant type', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockApprovedUser]);
|
|
fixture.detectChanges();
|
|
|
|
const rows = fixture.nativeElement.querySelectorAll('tbody tr');
|
|
const roleCell = rows[0].querySelectorAll('td')[2];
|
|
expect(roleCell?.textContent?.trim()).toBe('Unternehmen');
|
|
});
|
|
|
|
it('should display role as Privatperson for Private participant type', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockRejectedUser]);
|
|
fixture.detectChanges();
|
|
|
|
const rows = fixture.nativeElement.querySelectorAll('tbody tr');
|
|
const roleCell = rows[0].querySelectorAll('td')[2];
|
|
expect(roleCell?.textContent?.trim()).toBe('Privatperson');
|
|
});
|
|
|
|
it('should show status badge in pending users table', () => {
|
|
fixture.detectChanges();
|
|
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
req.flush([mockPendingUser]);
|
|
fixture.detectChanges();
|
|
|
|
const badge = fixture.nativeElement.querySelector('span.rounded-full');
|
|
expect(badge?.textContent?.trim()).toBe('Ausstehend');
|
|
});
|
|
|
|
it('should show status badge in all users table', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockApprovedUser]);
|
|
fixture.detectChanges();
|
|
|
|
const badge = fixture.nativeElement.querySelector('span.rounded-full');
|
|
expect(badge?.textContent?.trim()).toBe('Freigeschaltet');
|
|
});
|
|
|
|
it('should switch to all tab and show user data with role column', () => {
|
|
fixture.detectChanges();
|
|
const pendingReq = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
|
pendingReq.flush([]);
|
|
|
|
component.switchTab('all');
|
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
|
allReq.flush([mockApprovedUser, mockPendingUser]);
|
|
fixture.detectChanges();
|
|
|
|
const rows = fixture.nativeElement.querySelectorAll('tbody tr');
|
|
expect(rows.length).toBe(2);
|
|
|
|
const allHeaders = fixture.nativeElement.querySelectorAll('th');
|
|
const headerTexts: string[] = [];
|
|
for (let i = 0; i < allHeaders.length; i++) {
|
|
headerTexts.push(allHeaders[i].textContent?.trim() || '');
|
|
}
|
|
expect(headerTexts).toContain('Rolle');
|
|
});
|
|
});
|
|
});
|