Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dts 40144 deep linking rs #1736

Closed
wants to merge 15 commits into from
Closed
204 changes: 134 additions & 70 deletions UI/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,94 +1,158 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { Router, NavigationEnd, RouteConfigLoadStart, RouteConfigLoadEnd } from '@angular/router';
import { HttpService } from './services/http.service';
import { AppComponent } from './app.component';
import { SharedService } from './services/shared.service';
import { GetAuthService } from './services/getauth.service';
import { HttpService } from './services/http.service';
import { GoogleAnalyticsService } from './services/google-analytics.service';
import { GetAuthorizationService } from './services/get-authorization.service';
import { GetAuthService } from './services/getauth.service';
import { SharedService } from './services/shared.service';
import { Router, ActivatedRoute, NavigationEnd, RouteConfigLoadEnd, RouteConfigLoadStart, Route } from '@angular/router';
import { PrimeNGConfig } from 'primeng/api';
import { of } from 'rxjs';
import { APP_CONFIG, AppConfig } from './services/app.config';
import { FeatureFlagsService } from './services/feature-toggle.service';
import { HelperService } from './services/helper.service';
import { Location } from '@angular/common';
import { of, Subject } from 'rxjs';

describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let router: Router;
let gaService: GoogleAnalyticsService;
let httpService: HttpService;
let authorization: GetAuthorizationService;
let getAuthService: GetAuthService;
let sharedService: SharedService;
let primengConfig: PrimeNGConfig;
let originalLocation: Location;
let featureFlagsService: FeatureFlagsService;
let sharedService: jasmine.SpyObj<SharedService>;
let getAuthService: jasmine.SpyObj<GetAuthService>;
let httpService: jasmine.SpyObj<HttpService>;
let googleAnalyticsService: jasmine.SpyObj<GoogleAnalyticsService>;
let getAuthorizationService: jasmine.SpyObj<GetAuthorizationService>;
let helperService: jasmine.SpyObj<HelperService>;
let router: jasmine.SpyObj<Router>;
let location: jasmine.SpyObj<Location>;
let primengConfig: jasmine.SpyObj<PrimeNGConfig>;
let routerEvents: Subject<any>;

beforeEach(async () => {
const sharedServiceMock = jasmine.createSpyObj('SharedService', [
'setProjectQueryParamInFilters',
'setSprintQueryParamInFilters',
'getSelectedType',
'setSelectedBoard',
]);

const getAuthServiceMock = jasmine.createSpyObj('GetAuthService', ['checkAuth']);
const httpServiceMock = jasmine.createSpyObj('HttpService', [], { currentVersion: '1.0.0' });
const googleAnalyticsServiceMock = jasmine.createSpyObj('GoogleAnalyticsService', ['setPageLoad']);
const getAuthorizationServiceMock = jasmine.createSpyObj('GetAuthorizationService', ['getRole']);
const helperServiceMock = jasmine.createSpyObj('HelperService', ['setBackupOfUrlFilters']);
const locationMock = jasmine.createSpyObj('Location', ['path']);
const primengConfigMock = jasmine.createSpyObj('PrimeNGConfig', [], { ripple: true });

router = jasmine.createSpyObj('Router', ['events']);
routerEvents = new Subject<any>();

const routerMock = {
navigate: jasmine.createSpy('navigate'),
events: routerEvents, // Mock the read-only events property
};

const activatedRouteMock = {
queryParams: of({
projectId: '123',
sprintId: '456',
}),
};

await TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ RouterTestingModule, HttpClientTestingModule ],
providers: [ GoogleAnalyticsService, HttpService, GetAuthorizationService,
SharedService, PrimeNGConfig, GetAuthService, FeatureFlagsService ,
{ provide: APP_CONFIG, useValue: AppConfig }]
})
.compileComponents();
});
declarations: [AppComponent],
providers: [
{ provide: SharedService, useValue: sharedServiceMock },
{ provide: GetAuthService, useValue: getAuthServiceMock },
{ provide: HttpService, useValue: httpServiceMock },
{ provide: GoogleAnalyticsService, useValue: googleAnalyticsServiceMock },
{ provide: GetAuthorizationService, useValue: getAuthorizationServiceMock },
{ provide: HelperService, useValue: helperServiceMock },
{ provide: Router, useValue: routerMock },
{ provide: Location, useValue: locationMock },
{ provide: PrimeNGConfig, useValue: primengConfigMock },
{ provide: ActivatedRoute, useValue: activatedRouteMock },
],
});

TestBed.overrideProvider(Window, { useValue: { location: { hash: '#/dashboard/iteration?stateFilters=U29tZUVuY29kZWREYXRh' } } });

await TestBed.compileComponents();

beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
router = TestBed.inject(Router);
gaService = TestBed.inject(GoogleAnalyticsService);
httpService = TestBed.inject(HttpService);
authorization = TestBed.inject(GetAuthorizationService);
sharedService = TestBed.inject(SharedService);
primengConfig = TestBed.inject(PrimeNGConfig);
featureFlagsService = TestBed.inject(FeatureFlagsService)
spyOn(gaService, 'load').and.returnValue(Promise.resolve(['gaTagManager']));
jasmine.createSpy('checkAuth').and.returnValue(true);
spyOn(sharedService, 'setSelectedType');
spyOn(component.ga, 'setPageLoad');
fixture.detectChanges();

sharedService = TestBed.inject(SharedService) as jasmine.SpyObj<SharedService>;
getAuthService = TestBed.inject(GetAuthService) as jasmine.SpyObj<GetAuthService>;
httpService = TestBed.inject(HttpService) as jasmine.SpyObj<HttpService>;
googleAnalyticsService = TestBed.inject(GoogleAnalyticsService) as jasmine.SpyObj<GoogleAnalyticsService>;
getAuthorizationService = TestBed.inject(GetAuthorizationService) as jasmine.SpyObj<GetAuthorizationService>;
helperService = TestBed.inject(HelperService) as jasmine.SpyObj<HelperService>;
location = TestBed.inject(Location) as jasmine.SpyObj<Location>;
primengConfig = TestBed.inject(PrimeNGConfig) as jasmine.SpyObj<PrimeNGConfig>;
router = TestBed.inject(Router) as jasmine.SpyObj<Router>;

// Set default behaviors for spies
getAuthService.checkAuth.and.returnValue(true);
sharedService.getSelectedType.and.returnValue('Scrum');
location.path.and.returnValue('/dashboard/iteration');
});

it('should create', () => {
it('should create the component', () => {
expect(component).toBeTruthy();
});

it('should set authorized to true on init', () => {
it('should remove "newUI" from localStorage on initialization', () => {
spyOn(localStorage, 'removeItem');
component.ngOnInit();
expect(localStorage.removeItem).toHaveBeenCalledWith('newUI');
});

it('should set project and sprint filters from query params', () => {
component.ngOnInit();
expect(sharedService.setProjectQueryParamInFilters).toHaveBeenCalledWith('123');
expect(sharedService.setSprintQueryParamInFilters).toHaveBeenCalledWith('456');
});

it('should enable PrimeNG ripple effect', () => {
component.ngOnInit();
expect(primengConfig.ripple).toBeTrue();
});

it('should set authorized based on GetAuthService', () => {
component.ngOnInit();
expect(component.authorized).toBeTrue();
expect(getAuthService.checkAuth).toHaveBeenCalled();
});

it('should initialize with authorized set to true when user is authenticated', () => {
component.ngOnInit();
expect(component.authorized).toBe(true);
});

it('should enable ripple effect in PrimeNGConfig', () => {
component.ngOnInit();
expect(primengConfig.ripple).toBe(true);
});

it('should add class scrolled to header when window.scrollY is 200', () => {
const header = document.createElement('div');
header.className = 'header';
document.body.appendChild(header);
window.scrollY = 200;
component.onScroll(new Event('scroll'));
expect(header.classList.contains('scrolled')).toBe(false);
document.body.removeChild(header);
});

it('should remove the class `scrolled` from header when window.scrollY is 200', () => {
const header = document.createElement('div');
header.classList.add('scrolled');
document.body.appendChild(header);
window.scrollY = 200;
component.onScroll(new Event('scroll'));
expect(header.classList.contains('scrolled')).toBe(true);
document.body.removeChild(header);
});
it('should handle RouteConfigLoadStart and RouteConfigLoadEnd events', () => {
component.ngOnInit();

// Emit RouteConfigLoadStart event
routerEvents.next(new RouteConfigLoadStart({ path: 'mock-path' } as any));
expect(component.loadingRouteConfig).toBeTrue();

// Emit RouteConfigLoadEnd event
routerEvents.next(new RouteConfigLoadEnd({ path: 'mock-path' } as any));
expect(component.loadingRouteConfig).toBeFalse();
});

it('should handle NavigationEnd events for Google Analytics and refresh logic', () => {
component.ngOnInit();

routerEvents.next(
new NavigationEnd(1, '/dashboard/iteration', '/dashboard/iteration'),
);

expect(component.selectedTab).toBe('iteration');
expect(sharedService.setSelectedBoard).toHaveBeenCalledWith('iteration');
expect(googleAnalyticsService.setPageLoad).toHaveBeenCalledWith({
url: '/dashboard/iteration/Scrum',
userRole: getAuthorizationService.getRole(),
version: '1.0.0',
uiType: 'New',
});
});

xit('should decode and set state filters from URL hash', () => {
component.ngOnInit();
expect(helperService.setBackupOfUrlFilters).toHaveBeenCalledWith('SomeEncodedData');
});
});
52 changes: 44 additions & 8 deletions UI/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import { GoogleAnalyticsService } from './services/google-analytics.service';
import { GetAuthorizationService } from './services/get-authorization.service';
import { Router, RouteConfigLoadStart, RouteConfigLoadEnd, NavigationEnd, ActivatedRoute } from '@angular/router';
import { PrimeNGConfig } from 'primeng/api';
import { FeatureFlagsService } from './services/feature-toggle.service';
import { HelperService } from './services/helper.service';
import { Location } from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
Expand All @@ -34,11 +35,11 @@ import { FeatureFlagsService } from './services/feature-toggle.service';


export class AppComponent implements OnInit {

loadingRouteConfig: boolean;

authorized = <boolean>true;

refreshCounter: number = 0;
self: any = this;
selectedTab: string = '';
@HostListener('window:scroll', ['$event'])
onScroll(event) {
const header = document.querySelector('.header');
Expand All @@ -50,13 +51,12 @@ export class AppComponent implements OnInit {
}

constructor(private router: Router, private service: SharedService, private getAuth: GetAuthService, private httpService: HttpService, private primengConfig: PrimeNGConfig,
public ga: GoogleAnalyticsService, private authorisation: GetAuthorizationService, private route: ActivatedRoute, private feature: FeatureFlagsService) {
public ga: GoogleAnalyticsService, private authorisation: GetAuthorizationService, private route: ActivatedRoute, private helperService: HelperService, private location: Location) {
this.authorized = this.getAuth.checkAuth();
}

ngOnInit() {
localStorage.removeItem('newUI');

/** Fetch projectId and sprintId from query param and save it to global object */
this.route.queryParams
.subscribe(params => {
Expand All @@ -68,8 +68,7 @@ export class AppComponent implements OnInit {
if (sprintId) {
this.service.setSprintQueryParamInFilters(sprintId)
}
}
);
});

this.primengConfig.ripple = true;
this.authorized = this.getAuth.checkAuth();
Expand All @@ -90,8 +89,45 @@ export class AppComponent implements OnInit {
uiType: 'New'
};
this.ga.setPageLoad(data);

if (!this.refreshCounter) {
++this.refreshCounter;

let selectedTab = this.location.path();
selectedTab = selectedTab?.split('/')[2] ? selectedTab?.split('/')[2] : 'iteration';
selectedTab = selectedTab?.split(' ').join('-').toLowerCase();
this.selectedTab = selectedTab.split('?statefilters=')[0];
this.service.setSelectedBoard(this.selectedTab);

const urlPath = decodeURIComponent(window.location.hash);
const queryParamsIndex = urlPath.indexOf('?');
const decodedPath = decodeURIComponent(urlPath);

if (queryParamsIndex !== -1) {
const queryString = urlPath.slice(queryParamsIndex + 1);

// Parse query string into key-value pairs
const urlParams = new URLSearchParams(queryString);

let param = urlParams.get('stateFilters');
param = atob(param);
if (param.includes('###')) {
param = param.replace(/###/gi, '___');
}
console.log('Param:', param);

this.helperService.setBackupOfUrlFilters(param);

// this.router.navigate([], {
// queryParams: { 'stateFilters': param }, // Pass the object here
// relativeTo: this.route,
// queryParamsHandling: 'merge', // Merge with existing queryParams
// });
}
}
}

});
}

}
2 changes: 1 addition & 1 deletion UI/src/app/app.module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('AppModule', () => {
module = new AppModule();
TestBed.configureTestingModule({
imports: [AppModule],
providers: [
providers: [
{ provide: AppInitializerService, useValue: appInitializerServiceSpy }
]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ export class CapacityPlanningComponent implements OnInit {
}

getAssigneeRoles() {
if (!(this.projectAssigneeRoles.length > 0)) {
if (this.projectAssigneeRoles.length <= 0) {
this.http_service.getAssigneeRoles()
.subscribe(response => {
if (response && response?.success && response?.data) {
Expand All @@ -362,7 +362,7 @@ export class CapacityPlanningComponent implements OnInit {
}

getCapacityJiraAssignee(projectId) {
if (!(Object.keys(this.projectJiraAssignees).length > 0) || (this.projectJiraAssignees['basicProjectConfigId'] !== projectId)) {
if (Object.keys(this.projectJiraAssignees).length <= 0 || (this.projectJiraAssignees['basicProjectConfigId'] !== projectId)) {
this.jiraAssigneeLoader = true;
this.http_service.getJiraProjectAssignee(projectId)
.subscribe(response => {
Expand Down
Loading
Loading