f5021dff428602d0253b7683ca2280e7946ac15a
[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 { JobInfo } from "@interfaces/producer.types";
45 import { ProducerService } from "@services/ei/producer.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 jobInfo1 = {
55   info_job_identity: "job1",
56   info_type_identity: "type1",
57   owner: "owner1",
58   target_uri: "http://one",
59 } as JobInfo;
60 const jobInfo2 = {
61   info_job_identity: "job2",
62   info_type_identity: "type2",
63   owner: "owner2",
64   target_uri: "http://two",
65 } as JobInfo;
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: ProducerService, 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         info_job_identity: "job1",
242         info_job_data: {
243           jobparam2: "value2_job2",
244           jobparam3: "value3_job2",
245           jobparam1: "value1_job2",
246         },
247         target_uri: "http://one",
248       } as JobInfo;
249
250       let producerServiceSpy = TestBed.inject(ProducerService) as jasmine.SpyObj<ProducerService>;
251       producerServiceSpy.getProducerIds.and.returnValue(of(["producer1"]));
252       producerServiceSpy.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         let sort = loader.getHarness(MatSortHarness);
370         tick(10);
371
372         sort.then((value) => {
373           value.getSortHeaders({ sortDirection: "" }).then((headers) => {
374             expect(headers.length).toBe(5);
375
376             headers[0].click();
377             tick(10);
378             headers[0].isActive().then((value) => {
379               expect(value).toBe(true);
380             });
381             headers[0].getSortDirection().then((value) => {
382               expect(value).toBe("asc");
383             });
384
385             headers[0].click();
386             tick(10);
387             headers[0].getSortDirection().then((value) => {
388               expect(value).toBe("desc");
389             });
390           });
391         });
392         discardPeriodicTasks();
393       }));
394
395       it("should sort table asc and desc by first header", fakeAsync(() => {
396         setServiceSpy();
397         tick(0);
398
399         let sort = loader.getHarness(MatSortHarness);
400         tick(10);
401
402         sort.then((value) => {
403           loader
404             .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
405             .then((loadTable) => {
406               tick(10);
407               value.getSortHeaders().then((headers) => {
408                 headers[0].click();
409                 tick(10);
410                 headers[0].getSortDirection().then((direction) => {
411                   expect(direction).toBe("asc");
412                 });
413                 loadTable.getRows().then((jobRows) => {
414                   jobRows[0].getCellTextByColumnName().then((value) => {
415                     expect(expectedJob1Row).toEqual(
416                       jasmine.objectContaining(value)
417                     );
418                   });
419                 });
420
421                 headers[0].click();
422                 tick(10);
423                 headers[0].getSortDirection().then((direction) => {
424                   expect(direction).toBe("desc");
425                 });
426                 loadTable.getRows().then((jobRows) => {
427                   jobRows[jobRows.length - 1]
428                     .getCellTextByColumnName()
429                     .then((value) => {
430                       expect(expectedJob1Row).toEqual(
431                         jasmine.objectContaining(value)
432                       );
433                     });
434                 });
435               });
436             });
437         });
438         discardPeriodicTasks();
439       }));
440
441       it("should not sort when clicking on filtering box", fakeAsync(() => {
442         const expectedJobRow = {
443           jobId: "job1",
444           prodId: "producer2",
445           typeId: "type1",
446           owner: "owner1",
447           targetUri: "http://one",
448         };
449
450         setServiceSpy();
451         component.ngOnInit();
452         tick(0);
453
454         loader
455           .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
456           .then((loadTable) => {
457             loader
458               .getHarness(MatInputHarness.with({ selector: "#jobIdFilter" }))
459               .then((idFilter) => {
460                 tick(10);
461                 idFilter.setValue("").then((_) => {
462                   loadTable.getRows().then((jobRows) => {
463                     expect(jobRows.length).toEqual(4);
464                     jobRows[2].getCellTextByColumnName().then((value) => {
465                       expect(expectedJobRow).toEqual(
466                         jasmine.objectContaining(value)
467                       );
468                     });
469                   });
470                 });
471               });
472             loader
473               .getHarness(
474                 MatInputHarness.with({ selector: "#jobTypeIdFilter" })
475               )
476               .then((typeIdFilter) => {
477                 tick(10);
478                 typeIdFilter.setValue("").then((_) => {
479                   loadTable.getRows().then((jobRows) => {
480                     expect(jobRows.length).toEqual(4);
481                     jobRows[2].getCellTextByColumnName().then((value) => {
482                       expect(expectedJobRow).toEqual(
483                         jasmine.objectContaining(value)
484                       );
485                     });
486                   });
487                 });
488               });
489             loader
490               .getHarness(MatInputHarness.with({ selector: "#jobOwnerFilter" }))
491               .then((ownerFilter) => {
492                 tick(10);
493                 ownerFilter.setValue("").then((_) => {
494                   loadTable.getRows().then((jobRows) => {
495                     expect(jobRows.length).toEqual(4);
496                     jobRows[2].getCellTextByColumnName().then((value) => {
497                       expect(expectedJobRow).toEqual(
498                         jasmine.objectContaining(value)
499                       );
500                     });
501                   });
502                 });
503               });
504             loader
505               .getHarness(
506                 MatInputHarness.with({ selector: "#jobTargetUriFilter" })
507               )
508               .then((targetUriFilter) => {
509                 tick(10);
510                 targetUriFilter.setValue("").then((_) => {
511                   loadTable.getRows().then((jobRows) => {
512                     expect(jobRows.length).toEqual(4);
513                     jobRows[2].getCellTextByColumnName().then((value) => {
514                       expect(expectedJobRow).toEqual(
515                         jasmine.objectContaining(value)
516                       );
517                     });
518                   });
519                 });
520               });
521           });
522         discardPeriodicTasks();
523       }));
524     });
525
526     describe("#paging", () => {
527       it("should work properly on the table", fakeAsync(() => {
528         let producerServiceSpy = TestBed.inject(
529           ProducerService
530         ) as jasmine.SpyObj<ProducerService>;
531         producerServiceSpy.getProducerIds.and.returnValue(
532           of(["producer1", "producer2"])
533         );
534         producerServiceSpy.getJobsForProducer.and.returnValue(
535           of([jobInfo1, jobInfo2, jobInfo1])
536         );
537         tick(0);
538
539         loader.getHarness(MatPaginatorHarness).then((paging) => {
540           paging.setPageSize(5);
541
542           loader
543             .getHarness(MatTableHarness.with({ selector: "#jobsTable" }))
544             .then((loadTable) => {
545               loadTable.getRows().then((jobRows) => {
546                 expect(jobRows.length).toEqual(5);
547               });
548               paging.goToNextPage();
549               loadTable.getRows().then((jobRows) => {
550                 expect(jobRows.length).toEqual(1);
551                 jobRows[0].getCellTextByColumnName().then((value) => {
552                   const expectedRow = {
553                     jobId: "job1",
554                     prodId: "producer2",
555                     typeId: "type1",
556                     owner: "owner1",
557                     targetUri: "http://one",
558                   };
559                   expect(expectedRow).toContain(
560                     jasmine.objectContaining(value)
561                   );
562                 });
563               });
564             });
565         });
566         discardPeriodicTasks();
567       }));
568     });
569   });
570 });
571
572 function setServiceSpy() {
573   let producerServiceSpy = TestBed.inject(ProducerService) as jasmine.SpyObj<ProducerService>;
574   producerServiceSpy.getProducerIds.and.returnValue(of(["producer1", "producer2"]));
575   producerServiceSpy.getJobsForProducer.and.returnValue(of([jobInfo1, jobInfo2]));
576 }