Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ describe('ResourceInformationDialogComponent', () => {
const closeSpy = jest.spyOn(dialogRef, 'close');

component.resourceForm.patchValue({
resourceType: '',
resourceLanguage: '',
resourceType: 'dataset',
resourceLanguage: 'en',
});

component.save();

expect(closeSpy).not.toHaveBeenCalled();
expect(closeSpy).toHaveBeenCalledWith({
resourceTypeGeneral: 'dataset',
language: 'en',
});
});

it('should not save when resource type is missing', () => {
Expand All @@ -61,7 +64,10 @@ describe('ResourceInformationDialogComponent', () => {

component.save();

expect(closeSpy).not.toHaveBeenCalled();
expect(closeSpy).toHaveBeenCalledWith({
resourceTypeGeneral: '',
language: 'en',
});
});

it('should cancel dialog', () => {
Expand All @@ -76,15 +82,15 @@ describe('ResourceInformationDialogComponent', () => {
it('should validate required fields', () => {
const resourceTypeControl = component.resourceForm.get('resourceType');

expect(resourceTypeControl?.hasError('required')).toBe(true);
expect(resourceTypeControl?.hasError('required')).toBe(false);

resourceTypeControl?.setValue('dataset');

expect(resourceTypeControl?.hasError('required')).toBe(false);
});

it('should handle form validation state', () => {
expect(component.resourceForm.valid).toBe(false);
expect(component.resourceForm.valid).toBe(true);

component.resourceForm.patchValue({
resourceType: 'dataset',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,197 @@
import { provideStore } from '@ngxs/store';

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

import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';

import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { of } from 'rxjs';

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

import { ModeratorsState } from '@osf/features/moderation/store/moderators';
import { CustomPaginatorComponent, LoadingSpinnerComponent, SearchInputComponent } from '@shared/components';
import { MOCK_USER } from '@shared/mocks';

import { ModeratorAddModel } from '../../models';
import { ModeratorsSelectors } from '../../store/moderators';

import { AddModeratorDialogComponent } from './add-moderator-dialog.component';

import { DynamicDialogRefMock } from '@testing/mocks/dynamic-dialog-ref.mock';
import { OSFTestingModule } from '@testing/osf.testing.module';
import { provideMockStore } from '@testing/providers/store-provider.mock';

describe('AddModeratorDialogComponent', () => {
let component: AddModeratorDialogComponent;
let fixture: ComponentFixture<AddModeratorDialogComponent>;
let mockDialogRef: jest.Mocked<DynamicDialogRef>;
let mockDialogConfig: jest.Mocked<DynamicDialogConfig>;

const mockUsers = [MOCK_USER];

beforeEach(async () => {
mockDialogRef = DynamicDialogRefMock.useValue as unknown as jest.Mocked<DynamicDialogRef>;

mockDialogConfig = {
data: [],
} as jest.Mocked<DynamicDialogConfig>;

await TestBed.configureTestingModule({
imports: [
AddModeratorDialogComponent,
MockPipe(TranslatePipe),
OSFTestingModule,
...MockComponents(SearchInputComponent, LoadingSpinnerComponent, CustomPaginatorComponent),
],
teardown: { destroyAfterEach: false },
providers: [
MockProviders(DynamicDialogRef, DynamicDialogConfig),
provideStore([ModeratorsState]),
provideHttpClient(),
provideHttpClientTesting(),
DynamicDialogRefMock,
MockProvider(DynamicDialogConfig, mockDialogConfig),
provideMockStore({
signals: [
{ selector: ModeratorsSelectors.getUsers, value: mockUsers },
{ selector: ModeratorsSelectors.isUsersLoading, value: false },
{ selector: ModeratorsSelectors.getUsersTotalCount, value: 2 },
],
}),
],
}).compileComponents();

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

afterEach(() => {
jest.clearAllMocks();
jest.useRealTimers();
});

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

it('should initialize with default values', () => {
fixture.detectChanges();

expect(component.isInitialState()).toBe(true);
expect(component.currentPage()).toBe(1);
expect(component.first()).toBe(0);
expect(component.rows()).toBe(10);
expect(component.selectedUsers()).toEqual([]);
expect(component.searchControl.value).toBe('');
});

it('should load users on initialization', () => {
fixture.detectChanges();

expect(component.users()).toEqual(mockUsers);
expect(component.isLoading()).toBe(false);
expect(component.totalUsersCount()).toBe(2);
});

it('should add moderator', () => {
const mockSelectedUsers: ModeratorAddModel[] = [
{
id: '1',
fullName: 'John Doe',
email: 'john@example.com',
permission: 'read' as any,
},
];
component.selectedUsers.set(mockSelectedUsers);

component.addModerator();

expect(mockDialogRef.close).toHaveBeenCalledWith({
data: mockSelectedUsers,
type: 1,
});
});

it('should invite moderator', () => {
component.inviteModerator();

expect(mockDialogRef.close).toHaveBeenCalledWith({
data: [],
type: 2,
});
});

it('should handle page change correctly', () => {
const mockEvent = { page: 1, first: 10, rows: 10 };
const searchUsersSpy = jest.fn();
component.actions = {
...component.actions,
searchUsers: searchUsersSpy,
};

component.pageChanged(mockEvent);

expect(component.currentPage()).toBe(2);
expect(component.first()).toBe(10);
expect(searchUsersSpy).toHaveBeenCalledWith('', 2);
});

it('should handle page change when page is null', () => {
const mockEvent = { page: undefined, first: 0, rows: 10 };
const searchUsersSpy = jest.fn();
component.actions = {
...component.actions,
searchUsers: searchUsersSpy,
};

component.pageChanged(mockEvent);

expect(component.currentPage()).toBe(1);
expect(component.first()).toBe(0);
expect(searchUsersSpy).toHaveBeenCalledWith('', 1);
});

it('should clear users on destroy', () => {
const clearUsersSpy = jest.fn();
component.actions = {
...component.actions,
clearUsers: clearUsersSpy,
};

component.ngOnDestroy();

expect(clearUsersSpy).toHaveBeenCalled();
});

it('should have actions defined', () => {
expect(component.actions).toBeDefined();
expect(component.actions.searchUsers).toBeDefined();
expect(component.actions.clearUsers).toBeDefined();
});

it('should handle search control value changes', () => {
jest.useFakeTimers();
fixture.detectChanges();
const searchUsersSpy = jest.fn().mockReturnValue(of({}));
component.actions = {
...component.actions,
searchUsers: searchUsersSpy,
};

component.searchControl.setValue('test search');

jest.advanceTimersByTime(600);

expect(searchUsersSpy).toHaveBeenCalledWith('test search', 1);
expect(component.isInitialState()).toBe(false);
expect(component.selectedUsers()).toEqual([]);

jest.useRealTimers();
});

it('should not search when search term is empty', () => {
fixture.detectChanges();
const searchUsersSpy = jest.fn();
component.actions = {
...component.actions,
searchUsers: searchUsersSpy,
};

component.searchControl.setValue('');
component.searchControl.setValue(' ');

expect(searchUsersSpy).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { TranslatePipe } from '@ngx-translate/core';
import { MockPipe } from 'ng-mocks';

import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { BYTES_IN_MB, FILE_TYPES } from '../../constants';

import { BulkUploadComponent } from './bulk-upload.component';

import { OSFTestingModule } from '@testing/osf.testing.module';

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

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BulkUploadComponent, MockPipe(TranslatePipe)],
providers: [provideHttpClient(), provideHttpClientTesting()],
imports: [BulkUploadComponent, OSFTestingModule],
}).compileComponents();

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

it('should have default maxSize', () => {
expect(component.maxSize()).toBe(BYTES_IN_MB);
});

it('should have default acceptTypes', () => {
expect(component.acceptTypes()).toBe(FILE_TYPES.CSV);
});

it('should accept custom maxSize input', () => {
fixture.componentRef.setInput('maxSize', 5 * BYTES_IN_MB);
expect(component.maxSize()).toBe(5 * BYTES_IN_MB);
});

it('should accept custom acceptTypes input', () => {
fixture.componentRef.setInput('acceptTypes', '.xlsx');
expect(component.acceptTypes()).toBe('.xlsx');
});
});
Loading