From 7d556ecb9d05cc8171ecffe574def8bab766ebbc Mon Sep 17 00:00:00 2001 From: jayfyle <115472256+jayfyle@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:09:46 +0530 Subject: [PATCH] fix: Delegated Accounts Linting (#2429) * fixed linting * resovled comments * test: Code Coverage: Delegated Accounts Page (#2434) * coverage at 100 * resolved comments --------- Co-authored-by: Jay Budhadev --------- Co-authored-by: Jay Budhadev --- .../delegated-accounts.page.spec.ts | 173 ++++++++++++++++-- .../delegated-accounts.page.ts | 48 ++--- 2 files changed, 179 insertions(+), 42 deletions(-) diff --git a/src/app/fyle/delegated-accounts/delegated-accounts.page.spec.ts b/src/app/fyle/delegated-accounts/delegated-accounts.page.spec.ts index 1f8ed90b4c..1d7611cbfa 100644 --- a/src/app/fyle/delegated-accounts/delegated-accounts.page.spec.ts +++ b/src/app/fyle/delegated-accounts/delegated-accounts.page.spec.ts @@ -1,26 +1,173 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { IonicModule } from '@ionic/angular'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { of } from 'rxjs'; +import { getElementRef } from 'src/app/core/dom-helpers'; +import { apiEouRes, eouRes2, eouRes3 } from 'src/app/core/mock-data/extended-org-user.data'; +import { orgData1 } from 'src/app/core/mock-data/org.data'; +import { LoaderService } from 'src/app/core/services/loader.service'; +import { OrgUserService } from 'src/app/core/services/org-user.service'; +import { OrgService } from 'src/app/core/services/org.service'; +import { RecentLocalStorageItemsService } from 'src/app/core/services/recent-local-storage-items.service'; import { DelegatedAccountsPage } from './delegated-accounts.page'; -xdescribe('DelegatedAccountsPage', () => { +describe('DelegatedAccountsPage', () => { let component: DelegatedAccountsPage; let fixture: ComponentFixture; + let orgUserService: jasmine.SpyObj; + let orgService: jasmine.SpyObj; + let router: jasmine.SpyObj; + let loaderService: jasmine.SpyObj; + let activatedRoute: jasmine.SpyObj; + let recentLocalStorageItemsService: jasmine.SpyObj; - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [DelegatedAccountsPage], - imports: [IonicModule.forRoot()], - }).compileComponents(); + beforeEach(waitForAsync(() => { + const orgUserServiceSpy = jasmine.createSpyObj('OrgUserService', [ + 'switchToDelegator', + 'switchToDelegatee', + 'findDelegatedAccounts', + 'excludeByStatus', + ]); + const orgServiceSpy = jasmine.createSpyObj('OrgService', ['getCurrentOrg']); + const routerSpy = jasmine.createSpyObj('Router', ['navigate']); + const loaderServiceSpy = jasmine.createSpyObj('LoaderService', ['hideLoader', 'showLoader']); + const recentLocalStorageItemsServiceSpy = jasmine.createSpyObj('RecentLocalStorageItemsService', [ + 'clearRecentLocalStorageCache', + ]); - fixture = TestBed.createComponent(DelegatedAccountsPage); - component = fixture.componentInstance; - fixture.detectChanges(); - }) - ); + TestBed.configureTestingModule({ + declarations: [DelegatedAccountsPage], + imports: [IonicModule.forRoot(), FormsModule], + providers: [ + { + provide: ActivatedRoute, + useValue: { + snapshot: { + params: { + switchToOwn: true, + }, + }, + }, + }, + { + provide: OrgUserService, + useValue: orgUserServiceSpy, + }, + { + provide: OrgService, + useValue: orgServiceSpy, + }, + { + provide: Router, + useValue: routerSpy, + }, + { + provide: LoaderService, + useValue: loaderServiceSpy, + }, + { + provide: RecentLocalStorageItemsService, + useValue: recentLocalStorageItemsServiceSpy, + }, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + + fixture = TestBed.createComponent(DelegatedAccountsPage); + component = fixture.componentInstance; + + orgUserService = TestBed.inject(OrgUserService) as jasmine.SpyObj; + orgService = TestBed.inject(OrgService) as jasmine.SpyObj; + router = TestBed.inject(Router) as jasmine.SpyObj; + loaderService = TestBed.inject(LoaderService) as jasmine.SpyObj; + recentLocalStorageItemsService = TestBed.inject( + RecentLocalStorageItemsService + ) as jasmine.SpyObj; + activatedRoute = TestBed.inject(ActivatedRoute) as jasmine.SpyObj; + + fixture.detectChanges(); + })); it('should create', () => { expect(component).toBeTruthy(); }); + + it('switchToDelegatee(): should switch delegatee', fakeAsync(() => { + loaderService.showLoader.and.resolveTo(); + loaderService.hideLoader.and.resolveTo(); + recentLocalStorageItemsService.clearRecentLocalStorageCache.and.returnValue(null); + orgUserService.switchToDelegator.and.returnValue(of(apiEouRes)); + + component.switchToDelegatee(eouRes2); + tick(500); + + expect(loaderService.showLoader).toHaveBeenCalledTimes(1); + expect(loaderService.hideLoader).toHaveBeenCalledTimes(1); + expect(recentLocalStorageItemsService.clearRecentLocalStorageCache).toHaveBeenCalledTimes(1); + expect(orgUserService.switchToDelegator).toHaveBeenCalledOnceWith(eouRes2.ou); + expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_dashboard']); + })); + + describe('ionViewWillEnter():', () => { + it('should switch to own account if enabled', fakeAsync(() => { + loaderService.showLoader.and.resolveTo(null); + loaderService.hideLoader.and.resolveTo(null); + recentLocalStorageItemsService.clearRecentLocalStorageCache.and.returnValue(null); + orgUserService.switchToDelegatee.and.returnValue(of(apiEouRes)); + + component.ionViewWillEnter(); + tick(500); + + expect(loaderService.showLoader).toHaveBeenCalledTimes(1); + expect(loaderService.hideLoader).toHaveBeenCalledTimes(1); + expect(recentLocalStorageItemsService.clearRecentLocalStorageCache).toHaveBeenCalledTimes(1); + expect(orgUserService.switchToDelegatee).toHaveBeenCalledTimes(1); + expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_dashboard']); + })); + + it('should allow user to search and select a delegatee account', fakeAsync(() => { + component.searchDelegatees = getElementRef(fixture, '.delegated--search-input'); + const input = component.searchDelegatees.nativeElement as HTMLInputElement; + activatedRoute.snapshot.params.switchToOwn = null; + orgUserService.findDelegatedAccounts.and.returnValue(of([apiEouRes, eouRes2, eouRes3])); + orgService.getCurrentOrg.and.returnValue(of(orgData1[0])); + orgUserService.excludeByStatus.and.returnValue([eouRes2, eouRes3]); + + component.ionViewWillEnter(); + tick(500); + + input.value = 'ajain@fyle.in'; + input.dispatchEvent(new Event('keyup')); + tick(500); + + expect(component.delegatedAccList).toEqual([eouRes2, eouRes3]); + expect(orgUserService.findDelegatedAccounts).toHaveBeenCalledTimes(1); + expect(orgService.getCurrentOrg).toHaveBeenCalledTimes(1); + expect(orgUserService.excludeByStatus).toHaveBeenCalledWith([apiEouRes, eouRes2, eouRes3], 'DISABLED'); + })); + + it('should set delegatee acc list to empty array if no accounts are provided', fakeAsync(() => { + component.searchDelegatees = getElementRef(fixture, '.delegated--search-input'); + const input = component.searchDelegatees.nativeElement as HTMLInputElement; + activatedRoute.snapshot.params.switchToOwn = null; + orgUserService.findDelegatedAccounts.and.returnValue(of([])); + orgService.getCurrentOrg.and.returnValue(of(orgData1[0])); + orgUserService.excludeByStatus.and.returnValue(null); + + component.ionViewWillEnter(); + tick(500); + + input.value = 'ajain@fyle.in'; + input.dispatchEvent(new Event('keyup')); + tick(500); + + expect(component.delegatedAccList).toEqual([]); + expect(orgUserService.findDelegatedAccounts).toHaveBeenCalledTimes(1); + expect(orgService.getCurrentOrg).toHaveBeenCalledTimes(1); + expect(orgUserService.excludeByStatus).toHaveBeenCalledWith([], 'DISABLED'); + })); + }); }); diff --git a/src/app/fyle/delegated-accounts/delegated-accounts.page.ts b/src/app/fyle/delegated-accounts/delegated-accounts.page.ts index 8fbfea2748..a93535b0c2 100644 --- a/src/app/fyle/delegated-accounts/delegated-accounts.page.ts +++ b/src/app/fyle/delegated-accounts/delegated-accounts.page.ts @@ -1,30 +1,22 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { forkJoin, from, fromEvent, throwError } from 'rxjs'; -import { OrgUserService } from 'src/app/core/services/org-user.service'; +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { forkJoin, from, fromEvent } from 'rxjs'; +import { concatMap, distinctUntilChanged, finalize, map, shareReplay, startWith, switchMap } from 'rxjs/operators'; +import { ExtendedOrgUser } from 'src/app/core/models/extended-org-user.model'; import { LoaderService } from 'src/app/core/services/loader.service'; -import { - concatMap, - finalize, - catchError, - map, - startWith, - distinctUntilChanged, - switchMap, - tap, - shareReplay, -} from 'rxjs/operators'; -import { globalCacheBusterNotifier } from 'ts-cacheable'; -import { RecentLocalStorageItemsService } from 'src/app/core/services/recent-local-storage-items.service'; +import { OrgUserService } from 'src/app/core/services/org-user.service'; import { OrgService } from 'src/app/core/services/org.service'; +import { RecentLocalStorageItemsService } from 'src/app/core/services/recent-local-storage-items.service'; +import { globalCacheBusterNotifier } from 'ts-cacheable'; +import { User } from 'src/app/core/models/user.model'; @Component({ selector: 'app-delegated-accounts', templateUrl: './delegated-accounts.page.html', styleUrls: ['./delegated-accounts.page.scss'], }) -export class DelegatedAccountsPage implements OnInit { - @ViewChild('searchDelegatees') searchDelegatees: ElementRef; +export class DelegatedAccountsPage { + @ViewChild('searchDelegatees') searchDelegatees: ElementRef; delegatedAccList; @@ -41,7 +33,7 @@ export class DelegatedAccountsPage implements OnInit { private recentLocalStorageItemsService: RecentLocalStorageItemsService ) {} - switchToDelegatee(eou) { + switchToDelegatee(eou: ExtendedOrgUser): void { from(this.loaderService.showLoader('Switching Account')) .pipe( concatMap(() => { @@ -58,11 +50,9 @@ export class DelegatedAccountsPage implements OnInit { }); } - ngOnInit() {} - - ionViewWillEnter() { + ionViewWillEnter(): void { this.searchInput = ''; - const switchToOwn = this.activatedRoute.snapshot.params.switchToOwn; + const switchToOwn = this.activatedRoute.snapshot.params.switchToOwn as string; if (switchToOwn) { from(this.loaderService.showLoader('Switching Account')) @@ -87,18 +77,18 @@ export class DelegatedAccountsPage implements OnInit { this.currentOrg = res.currentOrg; }); - fromEvent(this.searchDelegatees.nativeElement, 'keyup') + fromEvent<{ srcElement: { value: string } }>(this.searchDelegatees.nativeElement, 'keyup') .pipe( - map((event: any) => event.srcElement.value), + map((event) => event.srcElement.value), startWith(''), distinctUntilChanged(), switchMap((searchText) => delegatedAccList$.pipe( map(({ delegatedAcc }) => this.orgUserService.excludeByStatus(delegatedAcc, 'DISABLED')), - map((delegatees) => - delegatees?.filter((delegatee) => + map((delegatees: ExtendedOrgUser[]) => + delegatees?.filter((delegatee: ExtendedOrgUser) => Object.values(delegatee.us).some( - (delegateeProp) => + (delegateeProp: User) => delegateeProp && delegateeProp.toString() && delegateeProp.toString().toLowerCase().includes(searchText.toLowerCase())