Skip to content

Commit 41e1ef7

Browse files
committed
test(unit-tests): added unit tests for add dialogs
1 parent 44e2ee4 commit 41e1ef7

File tree

4 files changed

+355
-153
lines changed

4 files changed

+355
-153
lines changed
Lines changed: 71 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
import { Store } from '@ngxs/store';
2+
13
import { MockComponents, MockProvider } from 'ng-mocks';
24

35
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
6+
import { PaginatorState } from 'primeng/paginator';
47

5-
import { of } from 'rxjs';
6-
7-
import { ComponentFixture, TestBed } from '@angular/core/testing';
8+
import { signal } from '@angular/core';
9+
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
810

911
import { CustomPaginatorComponent } from '@osf/shared/components/custom-paginator/custom-paginator.component';
1012
import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/loading-spinner.component';
1113
import { SearchInputComponent } from '@osf/shared/components/search-input/search-input.component';
1214

15+
import { AddModeratorType } from '../../enums';
1316
import { ModeratorAddModel } from '../../models';
1417
import { ModeratorsSelectors } from '../../store/moderators';
1518

@@ -23,17 +26,18 @@ import { provideMockStore } from '@testing/providers/store-provider.mock';
2326
describe('AddModeratorDialogComponent', () => {
2427
let component: AddModeratorDialogComponent;
2528
let fixture: ComponentFixture<AddModeratorDialogComponent>;
26-
let mockDialogRef: jest.Mocked<DynamicDialogRef>;
27-
let mockDialogConfig: jest.Mocked<DynamicDialogConfig>;
29+
let dialogRef: jest.Mocked<DynamicDialogRef>;
30+
let dialogConfig: DynamicDialogConfig;
31+
let store: Store;
2832

2933
const mockUsers = [MOCK_USER];
3034

3135
beforeEach(async () => {
32-
mockDialogRef = DynamicDialogRefMock.useValue as unknown as jest.Mocked<DynamicDialogRef>;
36+
dialogRef = DynamicDialogRefMock.useValue as unknown as jest.Mocked<DynamicDialogRef>;
3337

34-
mockDialogConfig = {
38+
dialogConfig = {
3539
data: [],
36-
} as jest.Mocked<DynamicDialogConfig>;
40+
} as DynamicDialogConfig;
3741

3842
await TestBed.configureTestingModule({
3943
imports: [
@@ -43,34 +47,30 @@ describe('AddModeratorDialogComponent', () => {
4347
],
4448
providers: [
4549
DynamicDialogRefMock,
46-
MockProvider(DynamicDialogConfig, mockDialogConfig),
50+
MockProvider(DynamicDialogConfig, dialogConfig),
4751
provideMockStore({
4852
signals: [
49-
{ selector: ModeratorsSelectors.getUsers, value: mockUsers },
53+
{ selector: ModeratorsSelectors.getUsers, value: signal(mockUsers) },
5054
{ selector: ModeratorsSelectors.isUsersLoading, value: false },
5155
{ selector: ModeratorsSelectors.getUsersTotalCount, value: 2 },
56+
{ selector: ModeratorsSelectors.getUsersNextLink, value: signal(null) },
57+
{ selector: ModeratorsSelectors.getUsersPreviousLink, value: signal(null) },
5258
],
5359
}),
5460
],
5561
}).compileComponents();
5662

63+
store = TestBed.inject(Store);
5764
fixture = TestBed.createComponent(AddModeratorDialogComponent);
5865
component = fixture.componentInstance;
59-
});
60-
61-
afterEach(() => {
62-
jest.clearAllMocks();
63-
jest.useRealTimers();
66+
fixture.detectChanges();
6467
});
6568

6669
it('should create', () => {
67-
fixture.detectChanges();
6870
expect(component).toBeTruthy();
6971
});
7072

7173
it('should initialize with default values', () => {
72-
fixture.detectChanges();
73-
7474
expect(component.isInitialState()).toBe(true);
7575
expect(component.currentPage()).toBe(1);
7676
expect(component.first()).toBe(0);
@@ -79,15 +79,13 @@ describe('AddModeratorDialogComponent', () => {
7979
expect(component.searchControl.value).toBe('');
8080
});
8181

82-
it('should load users on initialization', () => {
83-
fixture.detectChanges();
84-
82+
it('should load users from store', () => {
8583
expect(component.users()).toEqual(mockUsers);
8684
expect(component.isLoading()).toBe(false);
8785
expect(component.totalUsersCount()).toBe(2);
8886
});
8987

90-
it('should add moderator', () => {
88+
it('should close dialog with correct data for addModerator', () => {
9189
const mockSelectedUsers: ModeratorAddModel[] = [
9290
{
9391
id: '1',
@@ -100,100 +98,86 @@ describe('AddModeratorDialogComponent', () => {
10098

10199
component.addModerator();
102100

103-
expect(mockDialogRef.close).toHaveBeenCalledWith({
101+
expect(dialogRef.close).toHaveBeenCalledWith({
104102
data: mockSelectedUsers,
105-
type: 1,
103+
type: AddModeratorType.Search,
106104
});
107105
});
108106

109-
it('should invite moderator', () => {
107+
it('should close dialog with correct data for inviteModerator', () => {
110108
component.inviteModerator();
111109

112-
expect(mockDialogRef.close).toHaveBeenCalledWith({
110+
expect(dialogRef.close).toHaveBeenCalledWith({
113111
data: [],
114-
type: 2,
112+
type: AddModeratorType.Invite,
115113
});
116114
});
117115

118-
it('should handle page change correctly', () => {
119-
const mockEvent = { page: 1, first: 10, rows: 10 };
120-
const searchUsersSpy = jest.fn();
121-
component.actions = {
122-
...component.actions,
123-
searchUsers: searchUsersSpy,
124-
};
125-
126-
component.pageChanged(mockEvent);
127-
128-
expect(component.currentPage()).toBe(2);
129-
expect(component.first()).toBe(10);
130-
expect(searchUsersSpy).toHaveBeenCalledWith('', 2);
131-
});
132-
133-
it('should handle page change when page is null', () => {
134-
const mockEvent = { page: undefined, first: 0, rows: 10 };
135-
const searchUsersSpy = jest.fn();
136-
component.actions = {
137-
...component.actions,
138-
searchUsers: searchUsersSpy,
139-
};
116+
it('should handle pagination correctly', () => {
117+
const dispatchSpy = jest.spyOn(store, 'dispatch');
140118

141-
component.pageChanged(mockEvent);
119+
component.pageChanged({ first: 0 } as PaginatorState);
120+
expect(dispatchSpy).not.toHaveBeenCalled();
142121

122+
component.searchControl.setValue('test');
123+
component.pageChanged({ page: 0, first: 0, rows: 10 } as PaginatorState);
124+
expect(dispatchSpy).toHaveBeenCalled();
143125
expect(component.currentPage()).toBe(1);
144126
expect(component.first()).toBe(0);
145-
expect(searchUsersSpy).toHaveBeenCalledWith('', 1);
146127
});
147128

148-
it('should clear users on destroy', () => {
149-
const clearUsersSpy = jest.fn();
150-
component.actions = {
151-
...component.actions,
152-
clearUsers: clearUsersSpy,
153-
};
129+
it('should navigate to next page when link is available', () => {
130+
const nextLink = 'http://api.example.com/users?page=3';
131+
const originalSelect = store.select.bind(store);
132+
(store.select as jest.Mock) = jest.fn((selector) => {
133+
if (selector === ModeratorsSelectors.getUsersNextLink) {
134+
return signal(nextLink);
135+
}
136+
return originalSelect(selector);
137+
});
154138

155-
component.ngOnDestroy();
139+
Object.defineProperty(component, 'usersNextLink', {
140+
get: () => signal(nextLink),
141+
configurable: true,
142+
});
156143

157-
expect(clearUsersSpy).toHaveBeenCalled();
158-
});
144+
const dispatchSpy = jest.spyOn(store, 'dispatch');
145+
component.currentPage.set(2);
146+
component.pageChanged({ page: 2, first: 20, rows: 10 } as PaginatorState);
159147

160-
it('should have actions defined', () => {
161-
expect(component.actions).toBeDefined();
162-
expect(component.actions.searchUsers).toBeDefined();
163-
expect(component.actions.clearUsers).toBeDefined();
148+
expect(dispatchSpy).toHaveBeenCalled();
149+
expect(component.currentPage()).toBe(3);
150+
expect(component.first()).toBe(20);
164151
});
165152

166-
it('should handle search control value changes', () => {
167-
jest.useFakeTimers();
168-
fixture.detectChanges();
169-
const searchUsersSpy = jest.fn().mockReturnValue(of({}));
170-
component.actions = {
171-
...component.actions,
172-
searchUsers: searchUsersSpy,
173-
};
174-
175-
component.searchControl.setValue('test search');
153+
it('should debounce and filter search input', fakeAsync(() => {
154+
const dispatchSpy = jest.spyOn(store, 'dispatch');
176155

177-
jest.advanceTimersByTime(600);
156+
component.searchControl.setValue('t');
157+
tick(200);
158+
component.searchControl.setValue('test');
159+
tick(500);
178160

179-
expect(searchUsersSpy).toHaveBeenCalledWith('test search', 1);
161+
expect(dispatchSpy).toHaveBeenCalledTimes(1);
180162
expect(component.isInitialState()).toBe(false);
181163
expect(component.selectedUsers()).toEqual([]);
164+
}));
182165

183-
jest.useRealTimers();
184-
});
185-
186-
it('should not search when search term is empty', () => {
187-
fixture.detectChanges();
188-
const searchUsersSpy = jest.fn();
189-
component.actions = {
190-
...component.actions,
191-
searchUsers: searchUsersSpy,
192-
};
166+
it('should not search empty or whitespace values', fakeAsync(() => {
167+
const dispatchSpy = jest.spyOn(store, 'dispatch');
193168

194169
component.searchControl.setValue('');
170+
tick(500);
171+
expect(dispatchSpy).not.toHaveBeenCalled();
172+
195173
component.searchControl.setValue(' ');
174+
tick(500);
175+
expect(dispatchSpy).not.toHaveBeenCalled();
176+
}));
196177

197-
expect(searchUsersSpy).not.toHaveBeenCalled();
178+
it('should clear users on destroy', () => {
179+
const dispatchSpy = jest.spyOn(store, 'dispatch');
180+
component.ngOnDestroy();
181+
expect(dispatchSpy).toHaveBeenCalled();
198182
});
199183
});

0 commit comments

Comments
 (0)