Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,51 @@
import { TranslatePipe } from '@ngx-translate/core';
import { MockPipe } from 'ng-mocks';

import { ComponentRef } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MeetingsFeatureCardComponent } from './meetings-feature-card.component';

describe('MeetingsFeatureCardComponent', () => {
let component: MeetingsFeatureCardComponent;
let componentRef: ComponentRef<MeetingsFeatureCardComponent>;
let fixture: ComponentFixture<MeetingsFeatureCardComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MeetingsFeatureCardComponent],
imports: [MeetingsFeatureCardComponent, MockPipe(TranslatePipe, (value) => value)],
}).compileComponents();

fixture = TestBed.createComponent(MeetingsFeatureCardComponent);
component = fixture.componentInstance;
componentRef = fixture.componentRef;

componentRef.setInput('iconSrc', 'meeting-icon.svg');
componentRef.setInput('iconAlt', 'Meeting icon');
componentRef.setInput('titleKey', 'meetings.title');
componentRef.setInput('descriptionKey', 'meetings.description');

fixture.detectChanges();
});

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

it('should render icon with correct src and alt attributes', () => {
const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
expect(img).toBeTruthy();
expect(img.src).toContain('meeting-icon.svg');
expect(img.alt).toBe('Meeting icon');
});

it('should update icon inputs when setInput is called again', () => {
componentRef.setInput('iconAlt', 'New meeting icon');
componentRef.setInput('iconSrc', 'new-meeting-icon.svg');
fixture.detectChanges();

const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
expect(img.src).toContain('new-meeting-icon.svg');
expect(img.alt).toBe('New meeting icon');
});
});
6 changes: 6 additions & 0 deletions src/app/features/meetings/meetings.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { MeetingsComponent } from './meetings.component';

Expand All @@ -19,4 +20,9 @@ describe('MeetingsComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

it('should render router outlet', () => {
const routerOutlet = fixture.debugElement.query(By.css('router-outlet'));
expect(routerOutlet).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,76 @@
import { TranslateModule } from '@ngx-translate/core';
import { MockModule } from 'ng-mocks';
import { Store } from '@ngxs/store';

import { TranslatePipe } from '@ngx-translate/core';
import { MockComponents, MockPipe, MockProvider } from 'ng-mocks';

import { SortEvent } from 'primeng/api';
import { TablePageEvent } from 'primeng/table';

import { of } from 'rxjs';

import { DatePipe } from '@angular/common';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterModule } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';

import { MeetingsSelectors } from '@osf/features/meetings/store';
import { SearchInputComponent, SubHeaderComponent } from '@shared/components';
import { MOCK_MEETING, MOCK_MEETING_SUBMISSIONS, MOCK_STORE } from '@shared/mocks';

import { MeetingDetailsComponent } from './meeting-details.component';

const mockActivatedRoute = {
params: of({ id: 'test-meeting-id' }),
queryParams: of({}),
snapshot: {
params: { id: 'test-meeting-id' },
queryParams: {},
},
};

const mockRouter = {
navigate: jest.fn(),
url: '/',
createUrlTree: jest.fn(),
navigateByUrl: jest.fn(),
events: {
subscribe: jest.fn(),
},
};

describe('MeetingDetailsComponent', () => {
let component: MeetingDetailsComponent;
let fixture: ComponentFixture<MeetingDetailsComponent>;

beforeEach(async () => {
(MOCK_STORE.selectSignal as jest.Mock).mockImplementation((selector) => {
if (selector === MeetingsSelectors.getAllMeetingSubmissions) return () => MOCK_MEETING_SUBMISSIONS;
if (selector === MeetingsSelectors.getMeetingSubmissionsTotalCount) return () => MOCK_MEETING_SUBMISSIONS.length;
if (selector === MeetingsSelectors.isMeetingSubmissionsLoading) return () => false;
if (selector === MeetingsSelectors.getMeetingById) {
return () => (id: string) => (id === MOCK_MEETING.id ? MOCK_MEETING : null);
}
return () => null;
});

(MOCK_STORE.selectSnapshot as jest.Mock).mockImplementation((selector) => {
if (selector === MeetingsSelectors.getMeetingById) {
return (id: string) => (id === MOCK_MEETING.id ? MOCK_MEETING : null);
}
return () => null;
});

await TestBed.configureTestingModule({
imports: [MeetingDetailsComponent, MockModule(TranslateModule), MockModule(RouterModule)],
imports: [
MeetingDetailsComponent,
...MockComponents(SubHeaderComponent, SearchInputComponent),
MockPipe(TranslatePipe),
MockPipe(DatePipe),
],
providers: [
MockProvider(Store, MOCK_STORE),
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: Router, useValue: mockRouter },
],
}).compileComponents();

fixture = TestBed.createComponent(MeetingDetailsComponent);
Expand All @@ -23,4 +81,51 @@ describe('MeetingDetailsComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

it('should initialize with default table params', () => {
expect(component.tableParams().rows).toBeDefined();
expect(component.tableParams().firstRowIndex).toBe(0);
});

it('should open download link if present', () => {
const openSpy = jest.spyOn(window, 'open').mockImplementation();
const event = { stopPropagation: jest.fn() } as unknown as Event;
component.downloadSubmission(event, MOCK_MEETING_SUBMISSIONS[0]);
expect(openSpy).toHaveBeenCalledWith('https://example.com/file.pdf', '_blank');
openSpy.mockRestore();
});

it('should not open download link if not present', () => {
const openSpy = jest.spyOn(window, 'open').mockImplementation();
const event = { stopPropagation: jest.fn() } as unknown as Event;
component.downloadSubmission(event, MOCK_MEETING_SUBMISSIONS[1]);
expect(openSpy).not.toHaveBeenCalled();
openSpy.mockRestore();
});

it('should update query params in router on page change', () => {
const router = TestBed.inject(Router);
const navigateSpy = jest.spyOn(router, 'navigate');
component.onPageChange({ first: 10, rows: 10 } as TablePageEvent);
expect(navigateSpy).toHaveBeenCalledWith(
[],
expect.objectContaining({
queryParams: expect.objectContaining({ page: '2', size: '10' }),
queryParamsHandling: 'merge',
})
);
});

it('should update query params in router on sort', () => {
const router = TestBed.inject(Router);
const navigateSpy = jest.spyOn(router, 'navigate');
component.onSort({ field: 'title', order: 1 } as SortEvent);
expect(navigateSpy).toHaveBeenCalledWith(
[],
expect.objectContaining({
queryParams: expect.objectContaining({ sortColumn: 'title', sortOrder: 'asc' }),
queryParamsHandling: 'merge',
})
);
});
});
Loading