test(search-item-to-remit-dialog): enhance unit tests for component behavior and signal integration

This commit is contained in:
Lorenz Hilpert
2025-06-30 11:00:00 +02:00
parent 827aa565c5
commit 1663dcec73

View File

@@ -2,23 +2,46 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchItemToRemitDialogComponent } from './search-item-to-remit-dialog.component';
import { DialogRef, DIALOG_DATA } from '@angular/cdk/dialog';
import { DialogComponent } from '@isa/ui/dialog';
import { MockComponents } from 'ng-mocks';
import { TextButtonComponent } from '@isa/ui/buttons';
import { SearchItemToRemitListComponent } from './search-item-to-remit-list.component';
import { SelectRemiQuantityAndReasonComponent } from './select-remi-quantity-and-reason.component';
import { signal } from '@angular/core';
import { Item } from '@isa/catalogue/data-access';
import { By } from '@angular/platform-browser';
describe('SearchItemToRemitDialogComponent', () => {
let component: SearchItemToRemitDialogComponent;
let fixture: ComponentFixture<SearchItemToRemitDialogComponent>;
let mockDialogRef: {
updateSize: ReturnType<typeof vi.fn>;
close: ReturnType<typeof vi.fn>;
};
let mockDialogComponent: {
title: ReturnType<typeof signal>;
};
const mockItem = {
id: 1,
product: {
id: 1,
name: 'Test Product',
},
catalogAvailability: {},
} as unknown as Item;
beforeEach(async () => {
const mockDialogRef = {
updateSize: jest.fn(),
close: jest.fn(),
mockDialogRef = {
updateSize: vi.fn(),
close: vi.fn(),
};
mockDialogComponent = {
title: signal(''),
};
const mockData = { searchTerm: 'test' };
const mockDialogComponent = {
// Mock DialogComponent properties if needed
};
await TestBed.configureTestingModule({
imports: [SearchItemToRemitDialogComponent],
providers: [
@@ -26,15 +49,329 @@ describe('SearchItemToRemitDialogComponent', () => {
{ provide: DIALOG_DATA, useValue: mockData },
{ provide: DialogComponent, useValue: mockDialogComponent },
],
}).compileComponents();
})
.overrideComponent(SearchItemToRemitDialogComponent, {
remove: {
imports: [
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
],
},
add: {
imports: MockComponents(
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
),
},
})
.compileComponents();
fixture = TestBed.createComponent(SearchItemToRemitDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
describe('Component Setup and Initialization', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should initialize searchTerm from string data', () => {
fixture.detectChanges();
expect(component.searchTerm()).toBe('test');
});
it('should initialize searchTerm from Signal data', async () => {
const searchTermSignal = signal('signal test');
const mockSignalData = { searchTerm: searchTermSignal };
TestBed.resetTestingModule();
await TestBed.configureTestingModule({
imports: [SearchItemToRemitDialogComponent],
providers: [
{ provide: DialogRef, useValue: mockDialogRef },
{ provide: DIALOG_DATA, useValue: mockSignalData },
{ provide: DialogComponent, useValue: mockDialogComponent },
],
})
.overrideComponent(SearchItemToRemitDialogComponent, {
remove: {
imports: [
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
],
},
add: {
imports: MockComponents(
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
),
},
})
.compileComponents();
fixture = TestBed.createComponent(SearchItemToRemitDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
expect(component.searchTerm()).toBe('signal test');
// Test that it reacts to signal changes
searchTermSignal.set('updated signal test');
fixture.detectChanges();
expect(component.searchTerm()).toBe('updated signal test');
});
it('should initialize item signal as undefined', () => {
fixture.detectChanges();
expect(component.item()).toBeUndefined();
});
it('should extend DialogContentDirective', () => {
expect(component.dialogRef).toBeDefined();
expect(component.data).toBeDefined();
expect(component.close).toBeDefined();
});
});
});
describe('Signal and Effect Behavior', () => {
it('should update dialog size to auto when item is undefined', () => {
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('auto');
});
it('should update dialog size to 36rem when item is set', () => {
fixture.detectChanges();
mockDialogRef.updateSize.mockClear();
component.item.set(mockItem);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('36rem');
});
it('should update searchTerm when linkedSignal source changes', () => {
const searchTermSignal = signal('initial');
const mockSignalData = { searchTerm: searchTermSignal };
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [SearchItemToRemitDialogComponent],
providers: [
{ provide: DialogRef, useValue: mockDialogRef },
{ provide: DIALOG_DATA, useValue: mockSignalData },
{ provide: DialogComponent, useValue: mockDialogComponent },
],
})
.overrideComponent(SearchItemToRemitDialogComponent, {
remove: {
imports: [
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
],
},
add: {
imports: MockComponents(
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
),
},
})
.compileComponents();
fixture = TestBed.createComponent(SearchItemToRemitDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
expect(component.searchTerm()).toBe('initial');
searchTermSignal.set('updated');
fixture.detectChanges();
expect(component.searchTerm()).toBe('updated');
});
});
describe('Template Behavior', () => {
it('should show search list component when item is undefined', () => {
fixture.detectChanges();
const searchList = fixture.debugElement.query(
By.css('remi-search-item-to-remit-list'),
);
const selectQuantity = fixture.debugElement.query(
By.css('remi-select-remi-quantity-and-reason'),
);
expect(searchList).toBeTruthy();
expect(selectQuantity).toBeFalsy();
});
it('should show select quantity component when item is set', () => {
component.item.set(mockItem);
fixture.detectChanges();
const searchList = fixture.debugElement.query(
By.css('remi-search-item-to-remit-list'),
);
const selectQuantity = fixture.debugElement.query(
By.css('remi-select-remi-quantity-and-reason'),
);
expect(searchList).toBeFalsy();
expect(selectQuantity).toBeTruthy();
});
it('should show close button only when item is undefined', () => {
fixture.detectChanges();
let closeButton = fixture.debugElement.query(
By.css('button[uiTextButton]'),
);
expect(closeButton).toBeTruthy();
expect(closeButton.nativeElement.textContent.trim()).toBe('Schließen');
component.item.set(mockItem);
fixture.detectChanges();
closeButton = fixture.debugElement.query(By.css('button[uiTextButton]'));
expect(closeButton).toBeFalsy();
});
it('should call close with undefined when close button is clicked', () => {
fixture.detectChanges();
const closeButton = fixture.debugElement.query(
By.css('button[uiTextButton]'),
);
closeButton.nativeElement.click();
expect(mockDialogRef.close).toHaveBeenCalledWith(undefined);
});
it('should have correct button attributes', () => {
fixture.detectChanges();
const closeButton = fixture.debugElement.query(By.css('button'));
const buttonEl = closeButton.nativeElement;
expect(buttonEl.type).toBe('button');
expect(buttonEl.classList.contains('absolute')).toBe(true);
expect(buttonEl.classList.contains('top-1')).toBe(true);
expect(buttonEl.classList.contains('right-[1.33rem]')).toBe(true);
});
});
describe('DialogRef Integration', () => {
it('should call dialogRef.updateSize on initialization', () => {
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('auto');
});
it('should call dialogRef.updateSize when item changes', () => {
fixture.detectChanges();
mockDialogRef.updateSize.mockClear();
component.item.set(mockItem);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('36rem');
component.item.set(undefined);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('auto');
});
it('should inherit close method from DialogContentDirective', () => {
const closeSpy = vi.spyOn(component, 'close');
component.close(mockItem);
expect(closeSpy).toHaveBeenCalledWith(mockItem);
expect(mockDialogRef.close).toHaveBeenCalledWith(mockItem);
});
});
describe('Edge Cases and Error Handling', () => {
it('should handle empty searchTerm', async () => {
const emptyData = { searchTerm: '' };
TestBed.resetTestingModule();
await TestBed.configureTestingModule({
imports: [SearchItemToRemitDialogComponent],
providers: [
{ provide: DialogRef, useValue: mockDialogRef },
{ provide: DIALOG_DATA, useValue: emptyData },
{ provide: DialogComponent, useValue: mockDialogComponent },
],
})
.overrideComponent(SearchItemToRemitDialogComponent, {
remove: {
imports: [
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
],
},
add: {
imports: MockComponents(
TextButtonComponent,
SearchItemToRemitListComponent,
SelectRemiQuantityAndReasonComponent,
),
},
})
.compileComponents();
fixture = TestBed.createComponent(SearchItemToRemitDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
expect(component.searchTerm()).toBe('');
});
it('should handle multiple rapid item changes', () => {
fixture.detectChanges();
mockDialogRef.updateSize.mockClear();
// First change
component.item.set(mockItem);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('36rem');
// Second change
component.item.set(undefined);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('auto');
// Third change
component.item.set(mockItem);
fixture.detectChanges();
expect(mockDialogRef.updateSize).toHaveBeenCalledWith('36rem');
// Total calls
expect(mockDialogRef.updateSize).toHaveBeenCalledTimes(3);
});
it('should handle component destruction gracefully', () => {
fixture.detectChanges();
// Component destruction should not throw errors
expect(() => {
fixture.destroy();
}).not.toThrow();
});
it('should maintain data integrity', () => {
const originalData = { searchTerm: 'test' };
fixture.detectChanges();
// Data should remain unchanged
expect(component.data).toEqual(originalData);
expect(component.data.searchTerm).toBe('test');
});
});
});