Skip to content

Commit

Permalink
feat(*): Add tests (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arash-Azarpoor authored Sep 5, 2024
1 parent 60a31fd commit 276ab9d
Show file tree
Hide file tree
Showing 74 changed files with 2,520 additions and 986 deletions.
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = tseslint.config(
],
processor: angular.processInlineTemplates,
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@angular-eslint/directive-selector": [
"error",
{
Expand Down
82 changes: 74 additions & 8 deletions src/app/components/bread-crump/bread-crump.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,95 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { BreadCrumpComponent } from './bread-crump.component';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { Router, NavigationEnd, ActivatedRoute, UrlTree } from '@angular/router';
import { Subject } from 'rxjs';
import { By } from '@angular/platform-browser';

describe('BreadCrumpComponent', () => {
let component: BreadCrumpComponent;
let fixture: ComponentFixture<BreadCrumpComponent>;
const mockActivatedRoute = {
params: of({ id: 1 }),
snapshot: { params: { id: 1 } },
let mockRouter: {
events: Subject<any>;
url: string;
createUrlTree: jasmine.Spy;
serializeUrl: jasmine.Spy;
};
let mockActivatedRoute: { snapshot: any };

beforeEach(async () => {
mockRouter = {
events: new Subject<any>(),
url: '/',
createUrlTree: jasmine.createSpy('createUrlTree').and.callFake((commands: any[]) => {
return {
toString: () => commands.join('/'),
} as any as UrlTree;
}),
serializeUrl: jasmine.createSpy('serializeUrl').and.callFake((urlTree: UrlTree) => {
return urlTree.toString();
}),
};
mockActivatedRoute = { snapshot: { url: [] } };

await TestBed.configureTestingModule({
imports: [BreadCrumpComponent],
providers: [{ provide: ActivatedRoute, useValue: mockActivatedRoute }],
providers: [
{ provide: Router, useValue: mockRouter },
{ provide: ActivatedRoute, useValue: mockActivatedRoute }
],
}).compileComponents();

fixture = TestBed.createComponent(BreadCrumpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
it('SHOULD be created WHEN ever', () => {
expect(component).toBeTruthy();
});

it('SHOULD generate breadcrumbs based on the URL WHEN ever', () => {
// Arrange
mockRouter.url = '/dashboard/user/profile';

// Act
mockRouter.events.next(new NavigationEnd(1, mockRouter.url, mockRouter.url));
fixture.detectChanges();

expect(component.breadcrumbs).toEqual([
{ label: 'Dashboard', url: '/dashboard' },
{ label: 'User', url: '/dashboard/user' },
{ label: 'Profile', url: '/dashboard/user/profile' },
]);
});

it('SHOULD render breadcrumbs correctly in the template WHEN ever', () => {
// Arrange
mockRouter.url = '/user/profile';

// Act
mockRouter.events.next(new NavigationEnd(1, mockRouter.url, mockRouter.url));
fixture.detectChanges();

// Assert
const breadcrumbItems = fixture.debugElement.queryAll(By.css('nz-breadcrumb-item'));

expect(breadcrumbItems.length).toBe(3);

expect(breadcrumbItems[0].nativeElement.textContent.trim()).toContain('');
expect(breadcrumbItems[1].nativeElement.textContent.trim()).toContain('User');
expect(breadcrumbItems[2].nativeElement.textContent.trim()).toContain('Profile');
});

it('SHOULD handle the case with an empty URL correctly WHEN ever', () => {
// Arrange
mockRouter.url = '/';

// Act
mockRouter.events.next(new NavigationEnd(1, mockRouter.url, mockRouter.url));
fixture.detectChanges();

// Assert
const breadcrumbItems = fixture.debugElement.queryAll(By.css('nz-breadcrumb-item'));
expect(breadcrumbItems.length).toBe(1);
});
});
10 changes: 4 additions & 6 deletions src/app/components/bread-crump/bread-crump.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NgFor, NgIf } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import {NavigationEnd, Router, RouterLink } from '@angular/router';
import { NavigationEnd, Router, RouterLink } from '@angular/router';
import { NzBreadCrumbComponent, NzBreadCrumbItemComponent } from 'ng-zorro-antd/breadcrumb';
import { filter } from 'rxjs';

Expand All @@ -12,22 +12,20 @@ import { filter } from 'rxjs';
styleUrl: './bread-crump.component.scss',
})
export class BreadCrumpComponent implements OnInit {
breadcrumbs: {label: string, url: string}[] = [];
breadcrumbs: { label: string; url: string }[] = [];

constructor(private router: Router) {}

ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe(() => {
this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
this.generateBreadcrumbs();
});

this.generateBreadcrumbs();
}

private generateBreadcrumbs() {
const urlParts = this.router.url.split('/').filter(part => part);
const urlParts = this.router.url.split('/').filter((part) => part);
this.breadcrumbs = urlParts.map((part, index) => {
const url = '/' + urlParts.slice(0, index + 1).join('/');
const label = this.formatLabel(part);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('DashboardContentComponent', () => {
fixture.detectChanges();
});

it('should create', () => {
it('SHOULD be created WHEN ever', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export class DashboardContentComponent implements OnInit {
protected commentList: commentType[] = [];

ngOnInit(): void {
console.log(comments);

this.commentList = comments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
</div>
<div class="navbar__right">
<a nz-dropdown nzTrigger="click" [nzDropdownMenu]="menu" nzPlacement="bottomCenter" class="navbar__right__menu-button">
{{ userData.firstName[0]?.toUpperCase() }}. {{ userData.lastName[0]?.toUpperCase()
{{ userData.firstName[0].toUpperCase() }}. {{ userData.lastName[0].toUpperCase()
}}{{ userData.lastName.slice(1) }}
<span nz-icon nzType="down" nzTheme="outline" class="navbar__right__menu-button__icon"></span>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<div class="navbar__right__custom-menu">
<div class="navbar__right__custom-menu__header">
{{ userData.firstName[0]?.toUpperCase() }}{{ userData.firstName.slice(1) }}
{{ userData.lastName[0]?.toUpperCase() }}{{ userData.lastName.slice(1) }}
{{ userData.firstName[0].toUpperCase() }}{{ userData.firstName.slice(1) }}
{{ userData.lastName[0].toUpperCase() }}{{ userData.lastName.slice(1) }}
</div>
<ul nz-menu class="navbar__right__custom-menu__list">
<li nz-menu-item class="navbar__right__custom-menu__list__item" routerLink="/dashboard/profile">
Expand All @@ -31,7 +31,7 @@
<li nz-menu-divider class="navbar__right__custom-menu__list__divider"></li>
<li
nz-menu-item
class="navbar__right__custom-menu__list__item"
class="navbar__right__custom-menu__list__item navbar__right__custom-menu__list__item-logout"
(click)="logout()"
(keydown.enter)="logout()"
(keydown.space)="logout()"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,66 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NZ_ICONS, NzIconService } from 'ng-zorro-antd/icon';
import { MenuOutline, UserOutline, SettingOutline } from '@ant-design/icons-angular/icons';
import { DashboardNavbarComponent } from './dashboard-navbar.component';
import { provideHttpClient } from '@angular/common/http';
import { of } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, of } from 'rxjs';
import { ActivatedRoute, provideRouter } from '@angular/router';
import { UserData } from '../../models/user-data';
import { UserService } from '../../services/user/user.service';
import { NotificationService } from '../../services/notification/notification.service';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { routes } from '../../app.routes';
import { HttpClient } from '@angular/common/http';
import { DashboardGuardService } from '../../services/gaurds/dashboard-guard/dashboard-guard.service';

describe('DashboardNavbarComponent', () => {
let component: DashboardNavbarComponent;
let fixture: ComponentFixture<DashboardNavbarComponent>;
let mockUserService: Partial<UserService>;
let userDataSubject: BehaviorSubject<UserData>;
let mockNotificationService: Partial<NotificationService>;

const mockActivatedRoute = {
params: of({ id: 1 }),
snapshot: { params: { id: 1 } },
};
const initialUserData: UserData = {
id: 1,
username: 'testuser',
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
roles: ['admin'],
};
const httpSpy = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete', 'patch']);

beforeEach(async () => {
userDataSubject = new BehaviorSubject<UserData>(initialUserData);

mockUserService = {
userData$: userDataSubject.asObservable(),
};

mockNotificationService = {
createNotification: jasmine.createSpy('createNotification'),
};

await TestBed.configureTestingModule({
imports: [DashboardNavbarComponent],
providers: [
provideHttpClient(),
provideAnimationsAsync(),
NzIconService,
{
provide: NZ_ICONS,
useValue: [MenuOutline, SettingOutline, UserOutline],
},
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: UserService, useValue: mockUserService },
{ provide: NotificationService, useValue: mockNotificationService },
{
provide: DashboardGuardService,
useValue: { canActivate: () => of(true) },
},
{ provide: HttpClient, useValue: httpSpy },
provideRouter(routes),
],
}).compileComponents();

Expand All @@ -34,7 +70,50 @@ describe('DashboardNavbarComponent', () => {
fixture.detectChanges();
});

it('should create', () => {
it('SHOULD be created WHEN ever', () => {
expect(component).toBeTruthy();
});

it('SHOULD display user data correctly in the navbar WHEN ever', () => {
// Arrange
const compiled = fixture.nativeElement;
const userNameElement = compiled.querySelector('.navbar__right__menu-button');

// Act

// Assert
expect(userNameElement.textContent).toContain('J. Doe');
});

it('SHOULD display user data correctly in the navbar dropdown WHEN dropdown button clicked', async () => {
// Arrange
const dropdownButton = fixture.nativeElement.querySelector('.navbar__right__menu-button');

// Act
dropdownButton.click();
fixture.detectChanges();
await fixture.whenStable();

// Assert
const userNameElement = window.document.querySelector('.navbar__right__custom-menu__header');
expect(userNameElement?.textContent).toContain(' John Doe ');
});

it('SHOULD trigger logout WHEN logout button is clicked in the dropdown', async () => {
// Arrange
spyOn(component as any, 'logout');
fixture.detectChanges();
const dropdownButton = fixture.nativeElement.querySelector('.navbar__right__menu-button');

// Act
dropdownButton.click();
fixture.detectChanges();
await fixture.whenStable();

const logoutButton = window.document.querySelector('.navbar__right__custom-menu__list__item-logout');
logoutButton?.dispatchEvent(new Event('click'));

// Assert
expect((component as any).logout).toHaveBeenCalled();
});
});
Loading

0 comments on commit 276ab9d

Please sign in to comment.