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,4 +1,4 @@
import { MockProvider } from 'ng-mocks';
import { MockComponents, MockProvider } from 'ng-mocks';

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

Expand All @@ -13,84 +13,95 @@ import { CustomDialogServiceMockBuilder } from '@testing/providers/custom-dialog

import { EducationHistoryDialogComponent } from '../../education-history-dialog/education-history-dialog.component';
import { EmploymentHistoryDialogComponent } from '../../employment-history-dialog/employment-history-dialog.component';
import { IconComponent } from '../../icon/icon.component';
import { InfoIconComponent } from '../../info-icon/info-icon.component';
import { SelectComponent } from '../../select/select.component';

import { ContributorsTableComponent } from './contributors-table.component';

const makeTableParams = (overrides: Partial<TableParameters> = {}): TableParameters => ({
rows: 10,
paginator: true,
scrollable: false,
rowsPerPageOptions: [10, 25, 50],
totalRecords: 4,
firstRowIndex: 10,
defaultSortOrder: null,
defaultSortColumn: null,
...overrides,
});

describe('ContributorsTableComponent', () => {
let component: ContributorsTableComponent;
let fixture: ComponentFixture<ContributorsTableComponent>;
let mockCustomDialogService: ReturnType<CustomDialogServiceMockBuilder['build']>;

const tableParams: TableParameters = {
rows: 10,
paginator: true,
scrollable: false,
rowsPerPageOptions: [10, 25, 50],
totalRecords: 4,
firstRowIndex: 10,
defaultSortOrder: null,
defaultSortColumn: null,
};

beforeEach(() => {
mockCustomDialogService = CustomDialogServiceMockBuilder.create().build();

TestBed.configureTestingModule({
imports: [ContributorsTableComponent],
imports: [ContributorsTableComponent, ...MockComponents(SelectComponent, IconComponent, InfoIconComponent)],
providers: [provideOSFCore(), MockProvider(CustomDialogService, mockCustomDialogService)],
});

fixture = TestBed.createComponent(ContributorsTableComponent);
component = fixture.componentInstance;
fixture.componentRef.setInput('tableParams', tableParams);
fixture.componentRef.setInput('tableParams', makeTableParams());
fixture.detectChanges();
});

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

it('should compute isProject based on resourceType', () => {
it('should return true from isProject when resourceType is Project', () => {
fixture.componentRef.setInput('resourceType', ResourceType.Project);
fixture.detectChanges();
expect(component.isProject()).toBe(true);
});

it('should return false from isProject when resourceType is Registration', () => {
fixture.componentRef.setInput('resourceType', ResourceType.Registration);
fixture.detectChanges();
expect(component.isProject()).toBe(false);
});

it('should compute deactivatedContributors when list contains deactivated contributor', () => {
const contributors: ContributorModel[] = [
it('should return true from deactivatedContributors when at least one contributor is deactivated', () => {
fixture.componentRef.setInput('contributors', [
{ ...MOCK_CONTRIBUTOR, id: '1', deactivated: false },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '2', deactivated: true },
];

component.contributors.set(contributors);

]);
fixture.detectChanges();
expect(component.deactivatedContributors()).toBe(true);
});

it('should compute showLoadMore when loaded contributors are below total records', () => {
component.contributors.set([{ ...MOCK_CONTRIBUTOR, id: '1' }]);

expect(component.showLoadMore()).toBe(true);
it('should return false from deactivatedContributors when all contributors are active', () => {
fixture.componentRef.setInput('contributors', [
{ ...MOCK_CONTRIBUTOR, id: '1', deactivated: false },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '2', deactivated: false },
]);
fixture.detectChanges();
expect(component.deactivatedContributors()).toBe(false);
});

it('should compute showLoadMore as false when contributors length matches total records', () => {
const contributors: ContributorModel[] = [
{ ...MOCK_CONTRIBUTOR, id: '1' },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '2' },
{ ...MOCK_CONTRIBUTOR, id: '3' },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '4' },
];
component.contributors.set(contributors);
it('should return false from deactivatedContributors when contributor list is empty', () => {
fixture.componentRef.setInput('contributors', []);
fixture.detectChanges();
expect(component.deactivatedContributors()).toBe(false);
});

it('should default showLoadMore to false', () => {
expect(component.showLoadMore()).toBe(false);
});

it('should emit remove event when removeContributor is called', () => {
const contributor = { ...MOCK_CONTRIBUTOR, id: 'remove-id' };
it('should reflect showLoadMore as true when set by parent', () => {
fixture.componentRef.setInput('showLoadMore', true);
fixture.detectChanges();
expect(component.showLoadMore()).toBe(true);
});

it('should emit remove event with the given contributor when removeContributor is called', () => {
const contributor: ContributorModel = { ...MOCK_CONTRIBUTOR, id: 'remove-id' };
vi.spyOn(component.remove, 'emit');

component.removeContributor(contributor);
Expand All @@ -106,7 +117,7 @@ describe('ContributorsTableComponent', () => {
expect(component.loadMore.emit).toHaveBeenCalled();
});

it('should open education history dialog with contributor education data', () => {
it('should open EducationHistoryDialogComponent with contributor education data', () => {
const contributor: ContributorModel = {
...MOCK_CONTRIBUTOR,
id: 'education-id',
Expand All @@ -133,7 +144,19 @@ describe('ContributorsTableComponent', () => {
});
});

it('should open employment history dialog with contributor employment data', () => {
it('should open EducationHistoryDialogComponent with an empty education array', () => {
const contributor: ContributorModel = { ...MOCK_CONTRIBUTOR, id: 'no-education-id', education: [] };

component.openEducationHistory(contributor);

expect(mockCustomDialogService.open).toHaveBeenCalledWith(EducationHistoryDialogComponent, {
header: 'project.contributors.table.headers.education',
width: '552px',
data: [],
});
});

it('should open EmploymentHistoryDialogComponent with contributor employment data', () => {
const contributor: ContributorModel = {
...MOCK_CONTRIBUTOR,
id: 'employment-id',
Expand All @@ -160,16 +183,42 @@ describe('ContributorsTableComponent', () => {
});
});

it('should reorder contributors indices using table firstRowIndex', () => {
const contributors: ContributorModel[] = [
it('should open EmploymentHistoryDialogComponent with an empty employment array', () => {
const contributor: ContributorModel = { ...MOCK_CONTRIBUTOR, id: 'no-employment-id', employment: [] };

component.openEmploymentHistory(contributor);

expect(mockCustomDialogService.open).toHaveBeenCalledWith(EmploymentHistoryDialogComponent, {
header: 'project.contributors.table.headers.employment',
width: '552px',
data: [],
});
});

it('should reindex contributors starting from tableParams.firstRowIndex on row reorder', () => {
fixture.componentRef.setInput('tableParams', makeTableParams({ firstRowIndex: 10 }));
fixture.componentRef.setInput('contributors', [
{ ...MOCK_CONTRIBUTOR, id: '1', index: 0 },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '2', index: 1 },
{ ...MOCK_CONTRIBUTOR, id: '3', index: 2 },
];
component.contributors.set(contributors);
]);
fixture.detectChanges();

component.onRowReorder();

expect(component.contributors().map((c) => c.index)).toEqual([10, 11, 12]);
});

it('should reindex contributors from 0 when firstRowIndex is 0 on row reorder', () => {
fixture.componentRef.setInput('tableParams', makeTableParams({ firstRowIndex: 0 }));
fixture.componentRef.setInput('contributors', [
{ ...MOCK_CONTRIBUTOR, id: '1', index: 5 },
{ ...MOCK_CONTRIBUTOR_WITHOUT_HISTORY, id: '2', index: 6 },
]);
fixture.detectChanges();

component.onRowReorder();

expect(component.contributors().map((item) => item.index)).toEqual([10, 11, 12]);
expect(component.contributors().map((c) => c.index)).toEqual([0, 1]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { ContributorPermission } from '@osf/shared/enums/contributors/contributo
import { ResourceType } from '@osf/shared/enums/resource-type.enum';
import { CustomDialogService } from '@osf/shared/services/custom-dialog.service';
import { ContributorModel } from '@shared/models/contributors/contributor.model';
import { SelectOption } from '@shared/models/select-option.model';
import { TableParameters } from '@shared/models/table-parameters.model';

import { EducationHistoryDialogComponent } from '../../education-history-dialog/education-history-dialog.component';
Expand Down Expand Up @@ -61,10 +60,10 @@ export class ContributorsTableComponent {

customDialogService = inject(CustomDialogService);

readonly permissionsOptions: SelectOption[] = PERMISSION_OPTIONS;
readonly permissionsOptions = PERMISSION_OPTIONS;
readonly ContributorPermission = ContributorPermission;

skeletonData: ContributorModel[] = Array.from({ length: 3 }, () => ({}) as ContributorModel);
skeletonData = Array.from({ length: 3 }, () => ({}) as ContributorModel);

isProject = computed(() => this.resourceType() === ResourceType.Project);

Expand Down
Loading