|
| 1 | +import { Store } from '@ngxs/store'; |
| 2 | + |
1 | 3 | import { MockComponent } from 'ng-mocks'; |
2 | 4 |
|
| 5 | +import { of } from 'rxjs'; |
| 6 | + |
3 | 7 | import { ComponentFixture, TestBed } from '@angular/core/testing'; |
4 | 8 |
|
| 9 | +import { UserSelectors } from '@core/store/user'; |
5 | 10 | import { AffiliatedInstitutionSelectComponent } from '@osf/shared/components/affiliated-institution-select/affiliated-institution-select.component'; |
| 11 | +import { ComponentFormControls } from '@osf/shared/enums/create-component-form-controls.enum'; |
| 12 | +import { ToastService } from '@osf/shared/services/toast.service'; |
| 13 | +import { FetchUserInstitutions, InstitutionsSelectors } from '@osf/shared/stores/institutions'; |
| 14 | +import { FetchRegions, RegionsSelectors } from '@osf/shared/stores/regions'; |
| 15 | + |
| 16 | +import { CreateComponent, GetComponents, ProjectOverviewSelectors } from '../../store'; |
6 | 17 |
|
7 | 18 | import { AddComponentDialogComponent } from './add-component-dialog.component'; |
8 | 19 |
|
9 | | -describe.skip('AddComponentComponent', () => { |
| 20 | +import { MOCK_INSTITUTION } from '@testing/mocks/institution.mock'; |
| 21 | +import { MOCK_PROJECT } from '@testing/mocks/project.mock'; |
| 22 | +import { OSFTestingModule } from '@testing/osf.testing.module'; |
| 23 | +import { provideMockStore } from '@testing/providers/store-provider.mock'; |
| 24 | + |
| 25 | +describe('AddComponentDialogComponent', () => { |
10 | 26 | let component: AddComponentDialogComponent; |
11 | 27 | let fixture: ComponentFixture<AddComponentDialogComponent>; |
| 28 | + let store: Store; |
| 29 | + |
| 30 | + const mockRegions = [{ id: 'region-1', name: 'Region 1' }]; |
| 31 | + const mockUser = { id: 'user-1', defaultRegionId: 'user-region' } as any; |
| 32 | + const mockProject = { ...MOCK_PROJECT, id: 'proj-1', title: 'Project', tags: ['tag1'] }; |
| 33 | + const mockInstitutions = [MOCK_INSTITUTION]; |
| 34 | + const mockUserInstitutions = [MOCK_INSTITUTION, { ...MOCK_INSTITUTION, id: 'inst-2', name: 'Inst 2' }]; |
12 | 35 |
|
13 | 36 | beforeEach(async () => { |
14 | 37 | await TestBed.configureTestingModule({ |
15 | | - imports: [AddComponentDialogComponent, MockComponent(AffiliatedInstitutionSelectComponent)], |
| 38 | + imports: [AddComponentDialogComponent, OSFTestingModule, MockComponent(AffiliatedInstitutionSelectComponent)], |
| 39 | + providers: [ |
| 40 | + provideMockStore({ |
| 41 | + signals: [ |
| 42 | + { selector: RegionsSelectors.getRegions, value: mockRegions }, |
| 43 | + { selector: UserSelectors.getCurrentUser, value: mockUser }, |
| 44 | + { selector: ProjectOverviewSelectors.getProject, value: mockProject }, |
| 45 | + { selector: ProjectOverviewSelectors.getInstitutions, value: mockInstitutions }, |
| 46 | + { selector: RegionsSelectors.areRegionsLoading, value: false }, |
| 47 | + { selector: ProjectOverviewSelectors.getComponentsSubmitting, value: false }, |
| 48 | + { selector: InstitutionsSelectors.getUserInstitutions, value: mockUserInstitutions }, |
| 49 | + { selector: InstitutionsSelectors.areUserInstitutionsLoading, value: false }, |
| 50 | + ], |
| 51 | + }), |
| 52 | + ], |
16 | 53 | }).compileComponents(); |
17 | 54 |
|
18 | 55 | fixture = TestBed.createComponent(AddComponentDialogComponent); |
19 | 56 | component = fixture.componentInstance; |
| 57 | + store = TestBed.inject(Store); |
| 58 | + (store.dispatch as jest.Mock).mockReturnValue(of(void 0)); |
20 | 59 | fixture.detectChanges(); |
21 | 60 | }); |
22 | 61 |
|
23 | 62 | it('should create', () => { |
24 | 63 | expect(component).toBeTruthy(); |
25 | 64 | }); |
| 65 | + |
| 66 | + it('should initialize form with default values', () => { |
| 67 | + expect(component.componentForm.get(ComponentFormControls.Title)?.value).toBe(''); |
| 68 | + expect(Array.isArray(component.componentForm.get(ComponentFormControls.Affiliations)?.value)).toBe(true); |
| 69 | + expect(component.componentForm.get(ComponentFormControls.Description)?.value).toBe(''); |
| 70 | + expect(component.componentForm.get(ComponentFormControls.AddContributors)?.value).toBe(false); |
| 71 | + expect(component.componentForm.get(ComponentFormControls.AddTags)?.value).toBe(false); |
| 72 | + expect(['', 'user-region']).toContain(component.componentForm.get(ComponentFormControls.StorageLocation)?.value); |
| 73 | + }); |
| 74 | + |
| 75 | + it('should dispatch FetchRegions and FetchUserInstitutions on init', () => { |
| 76 | + expect(store.dispatch).toHaveBeenCalledWith(expect.any(FetchRegions)); |
| 77 | + expect(store.dispatch).toHaveBeenCalledWith(expect.any(FetchUserInstitutions)); |
| 78 | + }); |
| 79 | + |
| 80 | + it('should return store values from selectors', () => { |
| 81 | + expect(component.storageLocations()).toEqual(mockRegions); |
| 82 | + expect(component.currentUser()).toEqual(mockUser); |
| 83 | + expect(component.currentProject()).toEqual(mockProject); |
| 84 | + expect(component.institutions()).toEqual(mockInstitutions); |
| 85 | + expect(component.areRegionsLoading()).toBe(false); |
| 86 | + expect(component.isSubmitting()).toBe(false); |
| 87 | + expect(component.userInstitutions()).toEqual(mockUserInstitutions); |
| 88 | + expect(component.areUserInstitutionsLoading()).toBe(false); |
| 89 | + }); |
| 90 | + |
| 91 | + it('should set affiliations form control from selected institutions', () => { |
| 92 | + const institutions = [MOCK_INSTITUTION]; |
| 93 | + component.setSelectedInstitutions(institutions); |
| 94 | + expect(component.componentForm.get(ComponentFormControls.Affiliations)?.value).toEqual([MOCK_INSTITUTION.id]); |
| 95 | + }); |
| 96 | + |
| 97 | + it('should mark form as touched and not dispatch when submitForm with invalid form', () => { |
| 98 | + (store.dispatch as jest.Mock).mockClear(); |
| 99 | + component.componentForm.get(ComponentFormControls.Title)?.setValue(''); |
| 100 | + component.submitForm(); |
| 101 | + expect(component.componentForm.touched).toBe(true); |
| 102 | + const createCalls = (store.dispatch as jest.Mock).mock.calls.filter((c) => c[0] instanceof CreateComponent); |
| 103 | + expect(createCalls.length).toBe(0); |
| 104 | + }); |
| 105 | + |
| 106 | + it('should dispatch CreateComponent and on success close dialog, getComponents, showSuccess', () => { |
| 107 | + component.componentForm.get(ComponentFormControls.Title)?.setValue('New Component'); |
| 108 | + component.componentForm.get(ComponentFormControls.StorageLocation)?.setValue('region-1'); |
| 109 | + component.componentForm.get(ComponentFormControls.Affiliations)?.setValue([MOCK_INSTITUTION.id]); |
| 110 | + (store.dispatch as jest.Mock).mockClear(); |
| 111 | + |
| 112 | + component.submitForm(); |
| 113 | + |
| 114 | + expect(store.dispatch).toHaveBeenCalledWith( |
| 115 | + new CreateComponent(mockProject.id, 'New Component', '', [], 'region-1', [MOCK_INSTITUTION.id], false) |
| 116 | + ); |
| 117 | + expect(component.dialogRef.close).toHaveBeenCalled(); |
| 118 | + expect(store.dispatch).toHaveBeenCalledWith(expect.any(GetComponents)); |
| 119 | + expect(TestBed.inject(ToastService).showSuccess).toHaveBeenCalledWith( |
| 120 | + 'project.overview.dialog.toast.addComponent.success' |
| 121 | + ); |
| 122 | + }); |
| 123 | + |
| 124 | + it('should pass project tags when addTags is true', () => { |
| 125 | + component.componentForm.get(ComponentFormControls.Title)?.setValue('With Tags'); |
| 126 | + component.componentForm.get(ComponentFormControls.StorageLocation)?.setValue('region-1'); |
| 127 | + component.componentForm.get(ComponentFormControls.Affiliations)?.setValue([]); |
| 128 | + component.componentForm.get(ComponentFormControls.AddTags)?.setValue(true); |
| 129 | + (store.dispatch as jest.Mock).mockClear(); |
| 130 | + |
| 131 | + component.submitForm(); |
| 132 | + |
| 133 | + expect(store.dispatch).toHaveBeenCalledWith( |
| 134 | + new CreateComponent(mockProject.id, 'With Tags', '', mockProject.tags, 'region-1', [], false) |
| 135 | + ); |
| 136 | + }); |
| 137 | + |
| 138 | + it('should set storage location to user default region when control empty and regions loaded', () => { |
| 139 | + fixture = TestBed.createComponent(AddComponentDialogComponent); |
| 140 | + component = fixture.componentInstance; |
| 141 | + component.componentForm.get(ComponentFormControls.StorageLocation)?.setValue(''); |
| 142 | + fixture.detectChanges(); |
| 143 | + expect(component.componentForm.get(ComponentFormControls.StorageLocation)?.value).toBe('user-region'); |
| 144 | + }); |
| 145 | +}); |
| 146 | + |
| 147 | +describe('AddComponentDialogComponent when user has no default region', () => { |
| 148 | + let component: AddComponentDialogComponent; |
| 149 | + let fixture: ComponentFixture<AddComponentDialogComponent>; |
| 150 | + |
| 151 | + const mockRegions = [{ id: 'region-1', name: 'Region 1' }]; |
| 152 | + const mockProject = { ...MOCK_PROJECT, id: 'proj-1', title: 'Project', tags: ['tag1'] }; |
| 153 | + |
| 154 | + beforeEach(async () => { |
| 155 | + await TestBed.configureTestingModule({ |
| 156 | + imports: [AddComponentDialogComponent, OSFTestingModule, MockComponent(AffiliatedInstitutionSelectComponent)], |
| 157 | + providers: [ |
| 158 | + provideMockStore({ |
| 159 | + signals: [ |
| 160 | + { selector: RegionsSelectors.getRegions, value: mockRegions }, |
| 161 | + { selector: UserSelectors.getCurrentUser, value: null }, |
| 162 | + { selector: ProjectOverviewSelectors.getProject, value: mockProject }, |
| 163 | + { selector: ProjectOverviewSelectors.getInstitutions, value: [] }, |
| 164 | + { selector: RegionsSelectors.areRegionsLoading, value: false }, |
| 165 | + { selector: ProjectOverviewSelectors.getComponentsSubmitting, value: false }, |
| 166 | + { selector: InstitutionsSelectors.getUserInstitutions, value: [] }, |
| 167 | + { selector: InstitutionsSelectors.areUserInstitutionsLoading, value: false }, |
| 168 | + ], |
| 169 | + }), |
| 170 | + ], |
| 171 | + }).compileComponents(); |
| 172 | + |
| 173 | + fixture = TestBed.createComponent(AddComponentDialogComponent); |
| 174 | + component = fixture.componentInstance; |
| 175 | + component.componentForm.get(ComponentFormControls.StorageLocation)?.setValue(''); |
| 176 | + fixture.detectChanges(); |
| 177 | + }); |
| 178 | + |
| 179 | + it('should set storage location to first region when control empty', () => { |
| 180 | + expect(component.componentForm.get(ComponentFormControls.StorageLocation)?.value).toBe('region-1'); |
| 181 | + }); |
26 | 182 | }); |
0 commit comments