test(frontend): enhance AdminUserApprovalComponent tests with full coverage
Add comprehensive tests covering: - Tab navigation (pending/all) with signal verification - loadAllUsers() calls correct endpoint via generated AdminIAMService - Error handling for loadPendingUsers and loadAllUsers failures - Approve/reject user actions including undefined userId guards - Template rendering: pending tab with Freigeben/Ablehnen buttons - Template rendering: all users tab without action buttons - Status badge rendering in both tabs - Role column display (Unternehmen/Privatperson) - Empty state messages for both tabs - Duplicate Status column header bug fix verification - No reload of allUsers if already loaded
This commit is contained in:
parent
e46b21c8ca
commit
71ecf47948
@ -82,16 +82,14 @@ describe('AdminUserApprovalComponent', () => {
|
||||
expect(component.pendingUsers()[0].firstName).toBe('Max');
|
||||
});
|
||||
|
||||
it('should load all users when switching to all tab', () => {
|
||||
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('/admin/users') && !r.url.includes('/pending'),
|
||||
);
|
||||
const allReq = httpMock.expectOne((r) => r.url === '/api/admin/users');
|
||||
expect(allReq.request.method).toBe('GET');
|
||||
allReq.flush([mockPendingUser, mockApprovedUser, mockRejectedUser]);
|
||||
|
||||
@ -104,9 +102,7 @@ describe('AdminUserApprovalComponent', () => {
|
||||
req.flush([]);
|
||||
|
||||
component.switchTab('all');
|
||||
const allReq = httpMock.expectOne(
|
||||
(r) => r.url.includes('/admin/users') && !r.url.includes('/pending'),
|
||||
);
|
||||
const allReq = httpMock.expectOne((r) => r.url === '/api/admin/users');
|
||||
allReq.flush([]);
|
||||
expect(component.activeTab()).toBe('all');
|
||||
|
||||
@ -114,6 +110,49 @@ describe('AdminUserApprovalComponent', () => {
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
expect(allReqs.length).toBe(1);
|
||||
});
|
||||
|
||||
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 === '/api/admin/users');
|
||||
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');
|
||||
@ -175,6 +214,17 @@ describe('AdminUserApprovalComponent', () => {
|
||||
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'));
|
||||
@ -188,8 +238,45 @@ describe('AdminUserApprovalComponent', () => {
|
||||
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', () => {
|
||||
it('should render tab navigation with two tabs', () => {
|
||||
fixture.detectChanges();
|
||||
const req = httpMock.expectOne((r) => r.url.includes('/admin/users/pending'));
|
||||
req.flush([]);
|
||||
@ -211,7 +298,7 @@ describe('AdminUserApprovalComponent', () => {
|
||||
expect(activeTab?.textContent).toContain('Ausstehende Anträge');
|
||||
});
|
||||
|
||||
it('should show only one Status column header (no duplicate)', () => {
|
||||
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]);
|
||||
@ -226,5 +313,142 @@ describe('AdminUserApprovalComponent', () => {
|
||||
}
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
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 === '/api/admin/users');
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user