44fcb6ae93567db2ce37bfac9cf9a05b0dfcabc0
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / ei-coordinator / jobs-list / jobs-list.component.spec.ts
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2021 Nordix Foundation
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20 import { HarnessLoader } from "@angular/cdk/testing";
21 import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
22 import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
23 import {
24   async,
25   ComponentFixture,
26   discardPeriodicTasks,
27   fakeAsync,
28   TestBed,
29   tick,
30   flushMicrotasks,
31 } from "@angular/core/testing";
32 import { FormsModule, ReactiveFormsModule } from "@angular/forms";
33 import { MatFormFieldModule } from "@angular/material/form-field";
34 import { MatInputModule } from "@angular/material/input";
35 import { MatInputHarness } from "@angular/material/input/testing";
36 import { MatPaginatorModule } from "@angular/material/paginator";
37 import { MatSortModule } from "@angular/material/sort";
38 import { MatSortHarness } from "@angular/material/sort/testing";
39 import { MatPaginatorHarness } from "@angular/material/paginator/testing";
40 import { MatTableModule } from "@angular/material/table";
41 import { MatTableHarness } from "@angular/material/table/testing";
42 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
43 import { of } from "rxjs/observable/of";
44 import { EIJob } from "@interfaces/ei.types";
45 import { EIService } from "@services/ei/ei.service";
46 import { UiService } from "@services/ui/ui.service";
47
48 import { Job, JobsListComponent } from "./jobs-list.component";
49 import { Subscription } from "rxjs";
50
51 let component: JobsListComponent;
52 let fixture: ComponentFixture<JobsListComponent>;
53
54 const eijob1 = {
55   ei_job_identity: "job1",
56   ei_type_identity: "type1",
57   owner: "owner1",
58   target_uri: "http://one",
59 } as EIJob;
60 const eijob2 = {
61   ei_job_identity: "job2",
62   ei_type_identity: "type2",
63   owner: "owner2",
64   target_uri: "http://two",
65 } as EIJob;
66
67 const job1 = {
68   jobId: "job1",
69   typeId: "type1",
70   owner: "owner1",
71   targetUri: "http://one",
72   prodId: "producer1",
73 } as Job;
74 const job2 = {
75   jobId: "job2",
76   typeId: "type2",
77   owner: "owner2",
78   targetUri: "http://two",
79   prodId: "producer1",
80 } as Job;
81 const job3 = {
82   jobId: "job1",
83   typeId: "type1",
84   owner: "owner1",
85   targetUri: "http://one",
86   prodId: "producer2",
87 } as Job;
88 const job4 = {
89   jobId: "job2",
90   typeId: "type2",
91   owner: "owner2",
92   targetUri: "http://two",
93   prodId: "producer2",
94 } as Job;
95
96 describe("JobsListComponent", () => {
97   let loader: HarnessLoader;
98
99   beforeEach(async(() => {
100     const spy = jasmine.createSpyObj("EIService", [
101       "getProducerIds",
102       "getJobsForProducer",
103     ]);
104
105     TestBed.configureTestingModule({
106       imports: [
107         MatTableModule,
108         MatPaginatorModule,
109         FormsModule,
110         MatSortModule,
111         ReactiveFormsModule,
112         BrowserAnimationsModule,
113         MatFormFieldModule,
114         MatInputModule,
115       ],
116       schemas: [CUSTOM_ELEMENTS_SCHEMA],
117       declarations: [JobsListComponent],
118       providers: [{ provide: EIService, useValue: spy }, UiService],
119     })
120       .compileComponents()
121       .then(() => {
122         fixture = TestBed.createComponent(JobsListComponent);
123         component = fixture.componentInstance;
124         loader = TestbedHarnessEnvironment.loader(fixture);
125       });
126   }));
127
128   const expectedJob1Row = {
129     jobId: "job1",
130     prodId: "producer1",
131     typeId: "type1",
132     owner: "owner1",
133     targetUri: "http://one",
134   };
135
136   it("should create", () => {
137     expect(component).toBeTruthy();
138   });
139
140   describe("#content", () => {
141     it("should loadJobs", fakeAsync(() => {
142       setServiceSpy();
143       const newSub: Subscription = component.dataSubscription();
144       tick(0);
145
146       const actualJobs: Job[] = component.jobs();
147       expect(actualJobs.length).toEqual(4);
148       expect(actualJobs).toEqual([job1, job2, job3, job4]);
149       newSub.unsubscribe();
150     }));
151
152     it("should contain job table with correct columns", fakeAsync(() => {
153       setServiceSpy();
154       component.ngOnInit();
155       tick(0);
156
157       loader
158         .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
159         .then((loadTable) => {
160           loadTable.getHeaderRows().then((headerRow) => {
161             headerRow[0].getCellTextByColumnName().then((header) => {
162               expect(header).toEqual({
163                 jobId: "Job ID",
164                 prodId: "Producer ID",
165                 typeId: "Type ID",
166                 owner: "Owner",
167                 targetUri: "Target URI",
168               });
169             });
170           });
171         });
172
173       discardPeriodicTasks();
174     }));
175
176     it("should set correct dark mode from UIService", fakeAsync(() => {
177       setServiceSpy();
178       component.ngOnInit();
179       tick(0);
180
181       const uiService: UiService = TestBed.inject(UiService);
182       expect(component.darkMode).toBeTruthy();
183
184       uiService.darkModeState.next(false);
185       fixture.detectChanges();
186       expect(component.darkMode).toBeFalsy();
187       discardPeriodicTasks();
188     }));
189   });
190
191   describe("#jobsTable", () => {
192     it("should contain data after initialization", fakeAsync(() => {
193       setServiceSpy();
194       component.ngOnInit();
195       tick(0);
196
197       const expectedJobRows = [
198         expectedJob1Row,
199         {
200           jobId: "job2",
201           prodId: "producer1",
202           typeId: "type2",
203           owner: "owner2",
204           targetUri: "http://two",
205         },
206         {
207           jobId: "job1",
208           prodId: "producer2",
209           typeId: "type1",
210           owner: "owner1",
211           targetUri: "http://one",
212         },
213         {
214           jobId: "job2",
215           prodId: "producer2",
216           typeId: "type2",
217           owner: "owner2",
218           targetUri: "http://two",
219         },
220       ];
221
222       loader
223         .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
224         .then((loadTable) => {
225           loadTable.getRows().then((jobRows) => {
226             expect(jobRows.length).toEqual(4);
227             jobRows.forEach((row) => {
228               row.getCellTextByColumnName().then((values) => {
229                 expect(expectedJobRows).toContain(
230                   jasmine.objectContaining(values)
231                 );
232               });
233             });
234           });
235         });
236       discardPeriodicTasks();
237     }));
238
239     it("should display default values for non required properties ", fakeAsync(() => {
240       const jobMissingProperties = {
241         ei_job_identity: "job1",
242         ei_job_data: {
243           jobparam2: "value2_job2",
244           jobparam3: "value3_job2",
245           jobparam1: "value1_job2",
246         },
247         target_uri: "http://one",
248       } as EIJob;
249
250       let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj<EIService>;
251       eiServiceSpy.getProducerIds.and.returnValue(of(["producer1"]));
252       eiServiceSpy.getJobsForProducer.and.returnValue(
253         of([jobMissingProperties])
254       );
255
256       component.ngOnInit();
257       tick(0);
258       const expectedJobRow = {
259         jobId: "job1",
260         prodId: "producer1",
261         typeId: "< No type >",
262         owner: "< No owner >",
263         targetUri: "http://one",
264       };
265
266       loader
267         .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
268         .then((loadTable) => {
269           loadTable.getRows().then((jobRows) => {
270             jobRows[0].getCellTextByColumnName().then((value) => {
271               expect(expectedJobRow).toEqual(jasmine.objectContaining(value));
272             });
273           });
274         });
275       discardPeriodicTasks();
276     }));
277
278     it("filtering", fakeAsync(() => {
279       setServiceSpy();
280       component.ngOnInit();
281       tick(0);
282
283       loader
284         .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
285         .then((loadTable) => {
286           loader
287             .getHarness(MatInputHarness.with({ selector: "#jobIdFilter" }))
288             .then((idFilter) => {
289               tick(10);
290               idFilter.setValue("1").then((_) => {
291                 tick(10);
292                 loadTable.getRows().then((jobRows) => {
293                   expect(jobRows.length).toEqual(2);
294                   jobRows[0].getCellTextByColumnName().then((value) => {
295                     expect(expectedJob1Row).toEqual(
296                       jasmine.objectContaining(value)
297                     );
298                     idFilter.setValue("");
299                     flushMicrotasks();
300                   });
301                 });
302               });
303             });
304
305           loader
306             .getHarness(MatInputHarness.with({ selector: "#jobTypeIdFilter" }))
307             .then((typeIdFilter) => {
308               tick(10);
309               typeIdFilter.setValue("1").then((_) => {
310                 loadTable.getRows().then((jobRows) => {
311                   expect(jobRows.length).toEqual(2);
312                   jobRows[0].getCellTextByColumnName().then((value) => {
313                     expect(expectedJob1Row).toEqual(
314                       jasmine.objectContaining(value)
315                     );
316                     typeIdFilter.setValue("");
317                     flushMicrotasks();
318                   });
319                 });
320               });
321             });
322
323           loader
324             .getHarness(MatInputHarness.with({ selector: "#jobOwnerFilter" }))
325             .then((ownerFilter) => {
326               tick(10);
327               ownerFilter.setValue("1").then((_) => {
328                 loadTable.getRows().then((jobRows) => {
329                   expect(jobRows.length).toEqual(2);
330                   jobRows[0].getCellTextByColumnName().then((value) => {
331                     expect(expectedJob1Row).toEqual(
332                       jasmine.objectContaining(value)
333                     );
334                     ownerFilter.setValue("");
335                     flushMicrotasks();
336                   });
337                 });
338               });
339             });
340
341           loader
342             .getHarness(
343               MatInputHarness.with({ selector: "#jobTargetUriFilter" })
344             )
345             .then((targetUriFilter) => {
346               tick(10);
347               targetUriFilter.setValue("one").then((_) => {
348                 loadTable.getRows().then((jobRows) => {
349                   expect(jobRows.length).toEqual(2);
350                   jobRows[0].getCellTextByColumnName().then((value) => {
351                     expect(expectedJob1Row).toEqual(
352                       jasmine.objectContaining(value)
353                     );
354                     targetUriFilter.setValue("");
355                     flushMicrotasks();
356                   });
357                 });
358               });
359             });
360         });
361       discardPeriodicTasks();
362     }));
363
364     describe("#sorting", () => {
365       it("should verify sort functionality on the table", fakeAsync(() => {
366         setServiceSpy();
367         tick(0);
368
369         loader.getHarness(MatSortHarness).then((sort) => {
370           sort.getSortHeaders({ sortDirection: "" }).then((headers) => {
371             expect(headers.length).toBe(5);
372
373             headers[0].click().then((_) => {
374               headers[0].isActive().then((active) => {
375                 expect(active).toBe(true);
376               });
377               headers[0].getSortDirection().then((direction) => {
378                 expect(direction).toBe("asc");
379               });
380             });
381             headers[0].click().then((_) => {
382               headers[0].getSortDirection().then((direction) => {
383                 expect(direction).toBe("desc");
384               });
385             });
386           });
387         });
388         discardPeriodicTasks();
389       }));
390
391       it("should sort table asc and desc by first header", fakeAsync(() => {
392         setServiceSpy();
393         tick(0);
394
395         loader.getHarness(MatSortHarness).then((sort) => {
396           loader
397             .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
398             .then((loadTable) => {
399               sort.getSortHeaders().then((headers) => {
400                 headers[0].click().then((_) => {
401                   headers[0].getSortDirection().then((direction) => {
402                     expect(direction).toBe("");
403                   });
404                 });
405                 headers[0].click().then((_) => {
406                   headers[0].getSortDirection().then((direction) => {
407                     expect(direction).toBe("asc");
408                   });
409                 });
410                 loadTable.getRows().then((jobRows) => {
411                   jobRows[0].getCellTextByColumnName().then((value) => {
412                     expect(expectedJob1Row).toContain(
413                       jasmine.objectContaining(value)
414                     );
415                   });
416                 });
417                 headers[0].click().then((_) => {
418                   headers[0].getSortDirection().then((direction) => {
419                     expect(direction).toBe("desc");
420                   });
421                 });
422                 loadTable.getRows().then((jobRows) => {
423                   jobRows[jobRows.length - 1]
424                     .getCellTextByColumnName()
425                     .then((value) => {
426                       expect(expectedJob1Row).toContain(
427                         jasmine.objectContaining(value)
428                       );
429                     });
430                 });
431               });
432             });
433         });
434         discardPeriodicTasks();
435       }));
436
437       it("should not sort when clicking on filtering box", fakeAsync(() => {
438         const expectedJobRow = {
439           jobId: "job1",
440           prodId: "producer2",
441           typeId: "type1",
442           owner: "owner1",
443           targetUri: "http://one",
444         };
445
446         setServiceSpy();
447         component.ngOnInit();
448         tick(0);
449
450         loader
451           .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
452           .then((loadTable) => {
453             loader
454               .getHarness(MatInputHarness.with({ selector: "#jobIdFilter" }))
455               .then((idFilter) => {
456                 tick(10);
457                 idFilter.setValue("").then((_) => {
458                   loadTable.getRows().then((jobRows) => {
459                     expect(jobRows.length).toEqual(4);
460                     jobRows[2].getCellTextByColumnName().then((value) => {
461                       expect(expectedJobRow).toEqual(
462                         jasmine.objectContaining(value)
463                       );
464                     });
465                   });
466                 });
467               });
468             loader
469               .getHarness(
470                 MatInputHarness.with({ selector: "#jobTypeIdFilter" })
471               )
472               .then((typeIdFilter) => {
473                 tick(10);
474                 typeIdFilter.setValue("").then((_) => {
475                   loadTable.getRows().then((jobRows) => {
476                     expect(jobRows.length).toEqual(4);
477                     jobRows[2].getCellTextByColumnName().then((value) => {
478                       expect(expectedJobRow).toEqual(
479                         jasmine.objectContaining(value)
480                       );
481                     });
482                   });
483                 });
484               });
485             loader
486               .getHarness(MatInputHarness.with({ selector: "#jobOwnerFilter" }))
487               .then((ownerFilter) => {
488                 tick(10);
489                 ownerFilter.setValue("").then((_) => {
490                   loadTable.getRows().then((jobRows) => {
491                     expect(jobRows.length).toEqual(4);
492                     jobRows[2].getCellTextByColumnName().then((value) => {
493                       expect(expectedJobRow).toEqual(
494                         jasmine.objectContaining(value)
495                       );
496                     });
497                   });
498                 });
499               });
500             loader
501               .getHarness(
502                 MatInputHarness.with({ selector: "#jobTargetUriFilter" })
503               )
504               .then((targetUriFilter) => {
505                 tick(10);
506                 targetUriFilter.setValue("").then((_) => {
507                   loadTable.getRows().then((jobRows) => {
508                     expect(jobRows.length).toEqual(4);
509                     jobRows[2].getCellTextByColumnName().then((value) => {
510                       expect(expectedJobRow).toEqual(
511                         jasmine.objectContaining(value)
512                       );
513                     });
514                   });
515                 });
516               });
517           });
518         discardPeriodicTasks();
519       }));
520     });
521
522     describe("#paging", () => {
523       it("should work properly on the table", fakeAsync(() => {
524         let eiServiceSpy = TestBed.inject(
525           EIService
526         ) as jasmine.SpyObj<EIService>;
527         eiServiceSpy.getProducerIds.and.returnValue(
528           of(["producer1", "producer2"])
529         );
530         eiServiceSpy.getJobsForProducer.and.returnValue(
531           of([eijob1, eijob2, eijob1])
532         );
533         tick(0);
534
535         loader.getHarness(MatPaginatorHarness).then((paging) => {
536           paging.setPageSize(5);
537
538           loader
539             .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
540             .then((loadTable) => {
541               loadTable.getRows().then((jobRows) => {
542                 expect(jobRows.length).toEqual(5);
543               });
544               paging.goToNextPage();
545               loadTable.getRows().then((jobRows) => {
546                 expect(jobRows.length).toEqual(1);
547                 jobRows[0].getCellTextByColumnName().then((value) => {
548                   const expectedRow = {
549                     jobId: "job1",
550                     prodId: "producer2",
551                     typeId: "type1",
552                     owner: "owner1",
553                     targetUri: "http://one",
554                   };
555                   expect(expectedRow).toContain(
556                     jasmine.objectContaining(value)
557                   );
558                 });
559               });
560             });
561         });
562         discardPeriodicTasks();
563       }));
564     });
565   });
566 });
567
568 function setServiceSpy() {
569   let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj<EIService>;
570   eiServiceSpy.getProducerIds.and.returnValue(of(["producer1", "producer2"]));
571   eiServiceSpy.getJobsForProducer.and.returnValue(of([eijob1, eijob2]));
572 }