@@ -6,10 +6,16 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
6
6
import { MaterialModule } from 'src/app/shared/material.module' ;
7
7
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' ;
8
8
import { SharedModule } from 'src/app/shared/shared.module' ;
9
+ import { UsersServiceMock } from 'src/app/testing/users-service.mock' ;
10
+ import { LoadingService } from 'src/app/shared/services/loading.service' ;
11
+ import { Subject , of } from 'rxjs' ;
12
+ import { PageEvent } from '@angular/material/paginator' ;
9
13
10
14
describe ( 'UserListComponent' , ( ) => {
11
15
let component : UserListComponent ;
12
16
let fixture : ComponentFixture < UserListComponent > ;
17
+ let usersService : UsersService ;
18
+ let loadingService : LoadingService ;
13
19
14
20
beforeEach ( async ( ) => {
15
21
await TestBed . configureTestingModule ( {
@@ -20,15 +26,203 @@ describe('UserListComponent', () => {
20
26
BrowserAnimationsModule ,
21
27
SharedModule ,
22
28
] ,
23
- providers : [ UsersService ] ,
29
+ providers : [ { provide : UsersService , useClass : UsersServiceMock } ] ,
24
30
} ) . compileComponents ( ) ;
25
31
26
32
fixture = TestBed . createComponent ( UserListComponent ) ;
27
33
component = fixture . componentInstance ;
34
+ usersService = TestBed . inject ( UsersService ) ;
35
+ loadingService = TestBed . inject ( LoadingService ) ;
28
36
fixture . detectChanges ( ) ;
29
37
} ) ;
30
38
31
39
it ( 'should create' , ( ) => {
32
40
expect ( component ) . toBeTruthy ( ) ;
33
41
} ) ;
42
+
43
+ describe ( 'ngOnInit' , ( ) => {
44
+ it ( 'should initialize pagination settings' , ( ) => {
45
+ component . initializePagination ( ) ;
46
+ expect ( component . pageSize ) . toBe ( 10 ) ;
47
+ expect ( component . pageIndex ) . toBe ( 0 ) ;
48
+ expect ( component . totalUsers ) . toBe ( 0 ) ;
49
+ } ) ;
50
+
51
+ it ( 'should call getUsers' , ( ) => {
52
+ spyOn ( component , 'getUsers' ) . and . callThrough ( ) ;
53
+ spyOn ( loadingService , 'loadingOn' ) ;
54
+
55
+ component . getUsers ( ) ;
56
+ expect ( component . getUsers ) . toHaveBeenCalled ( ) ;
57
+ expect ( loadingService . loadingOn ) . toHaveBeenCalled ( ) ;
58
+ } ) ;
59
+ } ) ;
60
+
61
+ describe ( 'getPaginationData' , ( ) => {
62
+ it ( 'should call getUsers from UsersService and set users in MatTableDataSource' , ( done ) => {
63
+ spyOn ( usersService , 'getUsers' ) . and . callThrough ( ) ;
64
+ spyOn ( component , 'applySortingOnResponse' ) ;
65
+ spyOn ( loadingService , 'loadingOff' ) ;
66
+
67
+ const filterValue = 'John' ;
68
+ component . getPaginationData ( filterValue ) . subscribe ( ( users ) => {
69
+ expect ( usersService . getUsers ) . toHaveBeenCalledWith (
70
+ component . pageIndex ,
71
+ component . pageSize ,
72
+ filterValue
73
+ ) ;
74
+ expect ( component . applySortingOnResponse ) . toHaveBeenCalledWith ( users ) ;
75
+ done ( ) ;
76
+ } ) ;
77
+ } ) ;
78
+ } ) ;
79
+
80
+ describe ( 'onPageChange' , ( ) => {
81
+ it ( 'should update pageIndex and pageSize properties' , ( ) => {
82
+ const event : PageEvent = { pageIndex : 2 , pageSize : 10 , length : 50 } ;
83
+ component . onPageChange ( event ) ;
84
+
85
+ expect ( component . pageIndex ) . toBe ( 2 ) ;
86
+ expect ( component . pageSize ) . toBe ( 10 ) ;
87
+ } ) ;
88
+
89
+ it ( 'should call loadingOn method of loadingService' , ( ) => {
90
+ spyOn ( loadingService , 'loadingOn' ) ;
91
+ const event : PageEvent = { pageIndex : 0 , pageSize : 5 , length : 20 } ;
92
+ component . onPageChange ( event ) ;
93
+
94
+ expect ( loadingService . loadingOn ) . toHaveBeenCalled ( ) ;
95
+ } ) ;
96
+ } ) ;
97
+
98
+ describe ( 'filterUsers' , ( ) => {
99
+ beforeEach ( ( ) => {
100
+ spyOn ( loadingService , 'loadingOn' ) ;
101
+ spyOn ( component , 'getPaginationData' ) . and . returnValue ( of ( [ ] ) ) ;
102
+ } ) ;
103
+ it ( 'should do nothing when event or event.target is not provided' , ( ) => {
104
+ const event : any = null ;
105
+ component . filterUsers ( event ) ;
106
+ expect ( component . getPaginationData ) . not . toHaveBeenCalled ( ) ;
107
+ expect ( loadingService . loadingOn ) . not . toHaveBeenCalled ( ) ;
108
+ } ) ;
109
+ it ( 'should cancel previous API call and call loadingOn when a non-empty filter value is provided' , ( ) => {
110
+ const inputValue = 'example filter' ;
111
+ const event : any = { target : { value : inputValue } } ;
112
+
113
+ component . filterUsers ( event ) ;
114
+
115
+ expect ( component . getPaginationData ) . toHaveBeenCalledWith (
116
+ inputValue . toLowerCase ( )
117
+ ) ;
118
+ expect ( loadingService . loadingOn ) . toHaveBeenCalled ( ) ;
119
+ } ) ;
120
+
121
+ it ( 'should debounce the API call by 300ms' , ( done : DoneFn ) => {
122
+ const debounceTimeValue = 300 ;
123
+
124
+ const event : any = { target : { value : 'sample filter' } } ;
125
+ component . filterUsers ( event ) ;
126
+
127
+ expect ( component . getPaginationData ) . toHaveBeenCalledWith ( 'sample filter' ) ;
128
+
129
+ // Wait for the debounce time plus a little buffer (50ms) before checking the getPaginationData call count.
130
+ setTimeout ( ( ) => {
131
+ expect ( component . getPaginationData ) . toHaveBeenCalledTimes ( 1 ) ;
132
+ done ( ) ;
133
+ } , debounceTimeValue + 50 ) ;
134
+ } ) ;
135
+ it ( 'should call clearFilterUsers when an empty filter value is provided' , ( ) => {
136
+ const event : any = { target : { value : '' } } ;
137
+ spyOn ( component , 'clearFilterUsers' ) ;
138
+
139
+ component . filterUsers ( event ) ;
140
+
141
+ expect ( component . clearFilterUsers ) . toHaveBeenCalled ( ) ;
142
+ } ) ;
143
+ } ) ;
144
+ describe ( 'clearFilterUsers' , ( ) => {
145
+ it ( 'should call loadingOn method of loadingService' , ( ) => {
146
+ spyOn ( loadingService , 'loadingOn' ) ;
147
+ component . clearFilterUsers ( ) ;
148
+
149
+ expect ( loadingService . loadingOn ) . toHaveBeenCalled ( ) ;
150
+ } ) ;
151
+ it ( 'should set pageIndex to 0' , ( ) => {
152
+ component . pageIndex = 5 ; // Set pageIndex to a non-zero value.
153
+ component . clearFilterUsers ( ) ;
154
+
155
+ expect ( component . pageIndex ) . toBe ( 0 ) ;
156
+ } ) ;
157
+
158
+ it ( 'should call displayPagination method' , ( ) => {
159
+ spyOn ( component , 'displayPagination' ) ;
160
+ component . clearFilterUsers ( ) ;
161
+
162
+ expect ( component . displayPagination ) . toHaveBeenCalled ( ) ;
163
+ } ) ;
164
+
165
+ it ( 'should call getPaginationData' , ( ) => {
166
+ const mockObservable = of ( /* mock API response */ ) ;
167
+ spyOn ( component , 'getPaginationData' ) . and . returnValue ( of ( [ ] ) ) ;
168
+
169
+ component . clearFilterUsers ( ) ;
170
+ expect ( component . getPaginationData ) . toHaveBeenCalled ( ) ;
171
+ } ) ;
172
+ } ) ;
173
+
174
+ describe ( 'cancelPreviousAPICall' , ( ) => {
175
+ it ( 'should call next and complete on ngUnsubscribe$' , ( ) => {
176
+ const nextSpy = spyOn ( component [ 'ngUnsubscribe$' ] , 'next' ) ;
177
+ const completeSpy = spyOn ( component [ 'ngUnsubscribe$' ] , 'complete' ) ;
178
+
179
+ component . cancelPreviousAPICall ( ) ;
180
+
181
+ expect ( nextSpy ) . toHaveBeenCalledWith ( '' ) ;
182
+ expect ( completeSpy ) . toHaveBeenCalled ( ) ;
183
+ } ) ;
184
+ it ( 'should assign a new instance of Subject to ngUnsubscribe$' , ( ) => {
185
+ const previousSubject = component [ 'ngUnsubscribe$' ] ;
186
+
187
+ component . cancelPreviousAPICall ( ) ;
188
+
189
+ expect ( component [ 'ngUnsubscribe$' ] ) . not . toBe ( previousSubject ) ;
190
+ expect ( component [ 'ngUnsubscribe$' ] instanceof Subject ) . toBeTrue ( ) ;
191
+ } ) ;
192
+ } ) ;
193
+
194
+ it ( 'should set _hidePagination to true in hidePagination()' , ( ) => {
195
+ component . hidePagination ( ) ;
196
+ expect ( component . _hidePagination ) . toBeTrue ( ) ;
197
+ } ) ;
198
+
199
+ it ( 'should set _hidePagination to false in displayPagination()' , ( ) => {
200
+ component . displayPagination ( ) ;
201
+ expect ( component . _hidePagination ) . toBeFalse ( ) ;
202
+ } ) ;
203
+
204
+ describe ( 'clearFilterUsers' , ( ) => {
205
+ it ( 'should clear the input field value and call clearFilterUsers' , ( ) => {
206
+ const inputElement = document . createElement ( 'input' ) as HTMLInputElement ;
207
+ inputElement . value = 'Sample Filter' ;
208
+
209
+ spyOn ( component , 'clearFilterUsers' ) ;
210
+
211
+ component . cleanFilterInput ( inputElement ) ;
212
+
213
+ expect ( inputElement . value ) . toBe ( '' ) ;
214
+
215
+ expect ( component . clearFilterUsers ) . toHaveBeenCalled ( ) ;
216
+ } ) ;
217
+ } ) ;
218
+
219
+ it ( 'should call next and complete on ngUnsubscribe$' , ( ) => {
220
+ spyOn ( component [ 'ngUnsubscribe$' ] , 'next' ) ;
221
+ spyOn ( component [ 'ngUnsubscribe$' ] , 'complete' ) ;
222
+
223
+ component . ngOnDestroy ( ) ;
224
+
225
+ expect ( component [ 'ngUnsubscribe$' ] . next ) . toHaveBeenCalledWith ( '' ) ;
226
+ expect ( component [ 'ngUnsubscribe$' ] . complete ) . toHaveBeenCalled ( ) ;
227
+ } ) ;
34
228
} ) ;
0 commit comments