Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kaancayli committed May 10, 2024
1 parent 88dc2ae commit be78d72
Show file tree
Hide file tree
Showing 4 changed files with 414 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export class ProgressBarComponent {
@Input() title: string = '';

get percentage(): number {
return (this.currentValue / this.maxValue) * 100;
if (this.maxValue === 0) {
return 0;
}
return Math.min((this.currentValue / this.maxValue) * 100, 100);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CompetencyAccordionComponent } from 'src/main/webapp/app/course/competencies/competency-accordion/competency-accordion.component';
import { By } from '@angular/platform-browser';
import { Competency, CompetencyTaxonomy } from 'app/entities/competency.model';
import { Router } from '@angular/router';
import { Course } from 'app/entities/course.model';
import { ArtemisTestModule } from '../../../test.module';
import { CourseDashboardComponent } from 'app/overview/course-dashboard/course-dashboard.component';
import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe';
import { ArtemisTimeAgoPipe } from 'app/shared/pipes/artemis-time-ago.pipe';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe';
import { ProgressBarComponent } from 'app/shared/progress-bar/progress-bar.component';
import { CourseExerciseRowComponent } from 'app/overview/course-exercises/course-exercise-row.component';
import { SidePanelComponent } from 'app/shared/side-panel/side-panel.component';
import { TranslateDirective } from 'app/shared/language/translate.directive';
import { FeatureToggleHideDirective } from 'app/shared/feature-toggle/feature-toggle-hide.directive';
import { SubmissionResultStatusComponent } from 'app/overview/submission-result-status.component';
import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { CompetencyRingsComponent } from 'app/course/competencies/competency-rings/competency-rings.component';

describe('CompetencyAccordionComponent', () => {
let component: CompetencyAccordionComponent;
let fixture: ComponentFixture<CompetencyAccordionComponent>;
let router: Router;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ArtemisTestModule, HttpClientTestingModule, MockModule(NgbTooltipModule)],
declarations: [
CompetencyAccordionComponent,
MockPipe(HtmlForMarkdownPipe),
MockPipe(ArtemisTimeAgoPipe),
MockPipe(ArtemisTranslatePipe),
MockPipe(ArtemisDatePipe),
MockComponent(ProgressBarComponent),
MockComponent(CourseExerciseRowComponent),
MockComponent(SidePanelComponent),
MockDirective(TranslateDirective),
MockDirective(FeatureToggleHideDirective),
MockComponent(SubmissionResultStatusComponent),
MockComponent(CourseDashboardComponent),
MockComponent(CompetencyRingsComponent),
],
providers: [{ provide: Router, useValue: { navigate: jest.fn() } }],
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(CompetencyAccordionComponent);
component = fixture.componentInstance;
router = TestBed.inject(Router);
component.index = 1;
component.openedIndex = 0;
});
});

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

it('should render competency title', () => {
component.competency = { title: 'Test Competency' } as Competency;
fixture.detectChanges();
const titleElement = fixture.debugElement.queryAll(By.css('.competency-accordion-header h3'));
expect(titleElement[1].nativeElement.textContent).toContain('Test Competency');
});

it('should render progress bar', () => {
component.competency = { exercises: [{ completed: true }, { completed: false }] } as Competency;
fixture.detectChanges();
const progressBarElement = fixture.debugElement.query(By.css('jhi-progress-bar'));
expect(progressBarElement).toBeTruthy();
});

it('should toggle open state when toggle is called', () => {
component.open = false;
component.toggle();
expect(component.open).toBeTrue();
component.toggle();
expect(component.open).toBeFalse();
});

it('should render competency icon', () => {
component.competency = { taxonomy: CompetencyTaxonomy.CREATE } as Competency;
fixture.detectChanges();
const iconElement = fixture.debugElement.query(By.css('fa-icon'));
expect(iconElement).toBeTruthy();
});

it('should render competency exercises progress bar', () => {
component.competency = { exercises: [{ completed: true }, { completed: false }] } as Competency;
fixture.detectChanges();
const progressBarElement = fixture.debugElement.query(By.css('jhi-progress-bar'));
expect(progressBarElement).toBeTruthy();
});

it('should render competency lecture units progress bar', () => {
component.competency = { lectureUnits: [{ completed: true }, { completed: false }] } as Competency;
fixture.detectChanges();
const progressBarElement = fixture.debugElement.query(By.css('jhi-progress-bar'));
expect(progressBarElement).toBeTruthy();
});

it('should render competency rings', () => {
component.competency = { userProgress: [{ progress: 50, confidence: 75 }] } as Competency;
fixture.detectChanges();
const competencyRingsElement = fixture.debugElement.query(By.css('jhi-competency-rings'));
expect(competencyRingsElement).toBeTruthy();
});

it('should emit accordionToggle event when toggle is called', () => {
const toggleSpy = jest.spyOn(component.accordionToggle, 'emit');
component.toggle();
expect(toggleSpy).toHaveBeenCalledWith({ opened: true, index: component.index });
});

it('should navigate to competency detail page when navigateToCompetencyDetailPage is called', () => {
const navigateSpy = jest.spyOn(router, 'navigate');
component.course = { id: 1 } as Course;
component.competency = { id: 1 } as Competency;
component.navigateToCompetencyDetailPage(new Event('click'));
expect(navigateSpy).toHaveBeenCalledWith(['/courses', component.course.id, 'competencies', component.competency.id]);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CourseStorageService } from 'app/course/manage/course-storage.service';
import { CompetencyService } from 'app/course/competencies/competency.service';
import { ActivatedRoute, Router } from '@angular/router';
import { of } from 'rxjs';
import { Competency } from 'app/entities/competency.model';
import { By } from '@angular/platform-browser';
import { Exercise } from 'app/entities/exercise.model';
import { HttpResponse } from '@angular/common/http';
import { CourseDashboardComponent } from 'app/overview/course-dashboard/course-dashboard.component';
import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe';
import { ArtemisTimeAgoPipe } from 'app/shared/pipes/artemis-time-ago.pipe';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe';
import { CourseExerciseRowComponent } from 'app/overview/course-exercises/course-exercise-row.component';
import { SidePanelComponent } from 'app/shared/side-panel/side-panel.component';
import { TranslateDirective } from 'app/shared/language/translate.directive';
import { SubmissionResultStatusComponent } from 'app/overview/submission-result-status.component';
import { MockComponent, MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks';
import { ArtemisTestModule } from '../../../test.module';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { Course } from 'app/entities/course.model';
import { CompetencyAccordionComponent } from 'app/course/competencies/competency-accordion/competency-accordion.component';
import { ProgressBarComponent } from 'app/shared/progress-bar/progress-bar.component';
import { FeatureToggleHideDirective } from 'app/shared/feature-toggle/feature-toggle-hide.directive';
import { CompetencyRingsComponent } from 'app/course/competencies/competency-rings/competency-rings.component';

describe('CourseDashboardComponent', () => {
let component: CourseDashboardComponent;
let fixture: ComponentFixture<CourseDashboardComponent>;
let courseStorageService: CourseStorageService;
let competencyService: CompetencyService;
let getAllForCourseStudentDashboardSpy: jest.SpyInstance;
let router: Router;
const mockCourse = { id: 1 } as Course;
const mockRouter = {
navigate: jest.fn(),
};

const mockCompetencies = generateMockCompetenciesWithExercises(5);

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ArtemisTestModule, HttpClientTestingModule, MockModule(NgbTooltipModule)],
declarations: [
CourseDashboardComponent,
CompetencyAccordionComponent,
MockPipe(HtmlForMarkdownPipe),
MockPipe(ArtemisTimeAgoPipe),
MockPipe(ArtemisTranslatePipe),
MockPipe(ArtemisDatePipe),
MockComponent(ProgressBarComponent),
MockComponent(CourseExerciseRowComponent),
MockComponent(SidePanelComponent),
MockDirective(TranslateDirective),
MockDirective(FeatureToggleHideDirective),
MockComponent(SubmissionResultStatusComponent),
MockComponent(CompetencyRingsComponent),
],
providers: [
MockProvider(CourseStorageService),
MockProvider(CompetencyService),
{
provide: ActivatedRoute,
useValue: {
parent: {
parent: {
params: of({ competencyId: '1', courseId: '1' }),
},
},
},
},
{ provide: Router, useValue: mockRouter },
],
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(CourseDashboardComponent);
component = fixture.componentInstance;
courseStorageService = TestBed.inject(CourseStorageService);
jest.spyOn(courseStorageService, 'subscribeToCourseUpdates').mockReturnValue(of(mockCourse));
competencyService = TestBed.inject(CompetencyService);
const mockResponse: HttpResponse<Competency[]> = new HttpResponse({ body: mockCompetencies });
getAllForCourseStudentDashboardSpy = jest.spyOn(competencyService, 'getAllForCourseStudentDashboard').mockReturnValue(of(mockResponse));
router = TestBed.inject(Router);
fixture.detectChanges();
});
});

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

it('should set courseId on initialization', () => {
const params = { courseId: 1 };
component.ngOnInit();
expect(component.courseId).toEqual(params.courseId);
});

it('should call setCourse on initialization', () => {
const getCourseSpy = jest.spyOn(courseStorageService, 'getCourse').mockReturnValue(mockCourse);
component.ngOnInit();
expect(getCourseSpy).toHaveBeenCalledWith(component.courseId);
expect(component.course).toEqual(mockCourse);
});

it('should load competencies on initialization', () => {
component.ngOnInit();
expect(component.competencies).toEqual(mockCompetencies);
expect(getAllForCourseStudentDashboardSpy).toHaveBeenCalledWith(component.courseId);
});

it('should render competency accordions when competencies are loaded', () => {
component.ngOnInit();
fixture.detectChanges();
const competencyAccordions = fixture.debugElement.queryAll(By.css('jhi-competency-accordion'));
expect(competencyAccordions).toHaveLength(mockCompetencies.length);
});

it('should navigate to learning paths when button is clicked and learning paths are enabled', () => {
component.course = { learningPathsEnabled: true };
fixture.detectChanges();
const navigateSpy = jest.spyOn(router, 'navigate');
const button = fixture.debugElement.query(By.css('.btn'));
button.triggerEventHandler('click', null);
expect(navigateSpy).toHaveBeenCalledWith(['courses', component.courseId, 'learning-path']);
});

it('should respond to accordionToggle event from CompetencyAccordionComponent', () => {
component.ngOnInit();
fixture.detectChanges();
const competencyAccordions = fixture.debugElement.queryAll(By.css('jhi-competency-accordion'));
const firstAccordionComponent = competencyAccordions[0].componentInstance as CompetencyAccordionComponent;
const toggleSpy = jest.spyOn(firstAccordionComponent.accordionToggle, 'emit');
firstAccordionComponent.toggle();
expect(toggleSpy).toHaveBeenCalledWith({ opened: true, index: firstAccordionComponent.index });
expect(component.openedAccordionIndex).toEqual(firstAccordionComponent.index);
});

it('should only allow one accordion to be open at a time', () => {
component.ngOnInit();
fixture.detectChanges();
const competencyAccordions = fixture.debugElement.queryAll(By.css('jhi-competency-accordion'));
const firstAccordionComponent = competencyAccordions[0].componentInstance as CompetencyAccordionComponent;
const secondAccordionComponent = competencyAccordions[1].componentInstance as CompetencyAccordionComponent;

firstAccordionComponent.toggle();
fixture.detectChanges();
expect(firstAccordionComponent.open).toBeTrue();
expect(secondAccordionComponent.open).toBeFalse();

secondAccordionComponent.toggle();
fixture.detectChanges();
expect(firstAccordionComponent.open).toBeFalse();
expect(secondAccordionComponent.open).toBeTrue();
});
});

function generateMockCompetenciesWithExercises(count: number): Competency[] {
const competencies: Competency[] = [];
for (let i = 1; i <= count; i++) {
const competency: Competency = {
id: i,
title: `Competency ${i}`,
description: `Description for Competency ${i}`,
exercises: [
{
id: i,
title: `Exercise ${i}`,
} as Exercise,
{
id: i + 1,
title: `Exercise ${i + 1}`,
// Add other properties as needed
} as Exercise,
],
// Add other properties as needed
};
competencies.push(competency);
}
return competencies;
}
Loading

0 comments on commit be78d72

Please sign in to comment.