11import { Store } from '@ngxs/store' ;
22
3- import { MockComponent , MockProvider } from 'ng-mocks' ;
3+ import { MockComponents , MockProvider } from 'ng-mocks' ;
44
55import { DynamicDialogConfig , DynamicDialogRef } from 'primeng/dynamicdialog' ;
66
7- import { signal } from '@angular/core' ;
8- import { ComponentFixture , TestBed } from '@angular/core/testing' ;
7+ import { TestBed } from '@angular/core/testing' ;
98
109import { IconComponent } from '@osf/shared/components/icon/icon.component' ;
1110import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/loading-spinner.component' ;
11+ import { RegistryResourceType } from '@osf/shared/enums/registry-resource.enum' ;
1212
13+ import { RegistryResource } from '../../models' ;
1314import { RegistryResourcesSelectors } from '../../store/registry-resources' ;
1415import { ResourceFormComponent } from '../resource-form/resource-form.component' ;
1516
1617import { AddResourceDialogComponent } from './add-resource-dialog.component' ;
1718
18- import { DynamicDialogRefMock } from '@testing/mocks/dynamic-dialog-ref.mock' ;
19- import { TranslateServiceMock } from '@testing/mocks/translate.service.mock' ;
20- import { OSFTestingModule } from '@testing/osf.testing.module' ;
21- import { provideMockStore } from '@testing/providers/store-provider.mock' ;
19+ import { provideDynamicDialogRefMock } from '@testing/mocks/dynamic-dialog-ref.mock' ;
20+ import { provideOSFCore } from '@testing/osf.testing.provider' ;
21+ import { mergeSignalOverrides , provideMockStore , SignalOverride } from '@testing/providers/store-provider.mock' ;
22+
23+ const MOCK_RESOURCE : RegistryResource = {
24+ id : 'res-1' ,
25+ description : 'Test' ,
26+ finalized : false ,
27+ type : RegistryResourceType . Data ,
28+ pid : '10.1234/test' ,
29+ } ;
30+
31+ interface SetupOverrides {
32+ registryId ?: string ;
33+ selectorOverrides ?: SignalOverride [ ] ;
34+ }
35+
36+ function setup ( overrides : SetupOverrides = { } ) {
37+ const mockDialogConfig = { data : { id : overrides . registryId ?? 'registry-123' } } ;
38+
39+ const defaultSignals = [
40+ { selector : RegistryResourcesSelectors . getCurrentResource , value : null } ,
41+ { selector : RegistryResourcesSelectors . isCurrentResourceLoading , value : false } ,
42+ ] ;
43+
44+ const signals = mergeSignalOverrides ( defaultSignals , overrides . selectorOverrides ) ;
45+
46+ TestBed . configureTestingModule ( {
47+ imports : [
48+ AddResourceDialogComponent ,
49+ ...MockComponents ( LoadingSpinnerComponent , ResourceFormComponent , IconComponent ) ,
50+ ] ,
51+ providers : [
52+ provideOSFCore ( ) ,
53+ provideDynamicDialogRefMock ( ) ,
54+ MockProvider ( DynamicDialogConfig , mockDialogConfig ) ,
55+ provideMockStore ( { signals } ) ,
56+ ] ,
57+ } ) ;
58+
59+ const store = TestBed . inject ( Store ) ;
60+ const dialogRef = TestBed . inject ( DynamicDialogRef ) ;
61+ const fixture = TestBed . createComponent ( AddResourceDialogComponent ) ;
62+ const component = fixture . componentInstance ;
63+ fixture . detectChanges ( ) ;
64+
65+ return { fixture, component, store, dialogRef } ;
66+ }
2267
2368describe ( 'AddResourceDialogComponent' , ( ) => {
24- let component : AddResourceDialogComponent ;
25- let fixture : ComponentFixture < AddResourceDialogComponent > ;
26- let store : Store ;
27- let dialogRef : jest . Mocked < DynamicDialogRef > ;
28- let mockDialogConfig : jest . Mocked < DynamicDialogConfig > ;
29-
30- const mockRegistryId = 'registry-123' ;
31-
32- beforeEach ( async ( ) => {
33- mockDialogConfig = {
34- data : {
35- id : mockRegistryId ,
36- } ,
37- } as jest . Mocked < DynamicDialogConfig > ;
38-
39- await TestBed . configureTestingModule ( {
40- imports : [
41- AddResourceDialogComponent ,
42- OSFTestingModule ,
43- MockComponent ( LoadingSpinnerComponent ) ,
44- MockComponent ( ResourceFormComponent ) ,
45- MockComponent ( IconComponent ) ,
46- ] ,
47- providers : [
48- DynamicDialogRefMock ,
49- TranslateServiceMock ,
50- MockProvider ( DynamicDialogConfig , mockDialogConfig ) ,
51- provideMockStore ( {
52- signals : [
53- { selector : RegistryResourcesSelectors . getCurrentResource , value : signal ( null ) } ,
54- { selector : RegistryResourcesSelectors . isCurrentResourceLoading , value : signal ( false ) } ,
55- ] ,
56- } ) ,
57- ] ,
58- } ) . compileComponents ( ) ;
59-
60- fixture = TestBed . createComponent ( AddResourceDialogComponent ) ;
61- component = fixture . componentInstance ;
62- store = TestBed . inject ( Store ) ;
63- dialogRef = TestBed . inject ( DynamicDialogRef ) as jest . Mocked < DynamicDialogRef > ;
64- fixture . detectChanges ( ) ;
65- } ) ;
66-
67- it ( 'should create' , ( ) => {
68- expect ( component ) . toBeTruthy ( ) ;
69- } ) ;
69+ it ( 'should create with default values' , ( ) => {
70+ const { component } = setup ( ) ;
7071
71- it ( 'should initialize with default values' , ( ) => {
72+ expect ( component ) . toBeTruthy ( ) ;
7273 expect ( component . doiDomain ) . toBe ( 'https://doi.org/' ) ;
73- expect ( component . inputLimits ) . toBeDefined ( ) ;
7474 expect ( component . isResourceConfirming ( ) ) . toBe ( false ) ;
7575 expect ( component . isPreviewMode ( ) ) . toBe ( false ) ;
76- expect ( component . resourceOptions ( ) ) . toBeDefined ( ) ;
7776 } ) ;
7877
7978 it ( 'should initialize form with empty values' , ( ) => {
79+ const { component } = setup ( ) ;
80+
8081 expect ( component . form . get ( 'pid' ) ?. value ) . toBe ( '' ) ;
8182 expect ( component . form . get ( 'resourceType' ) ?. value ) . toBe ( '' ) ;
8283 expect ( component . form . get ( 'description' ) ?. value ) . toBe ( '' ) ;
8384 } ) ;
8485
8586 it ( 'should validate pid with DOI validator' , ( ) => {
87+ const { component } = setup ( ) ;
8688 const pidControl = component . form . get ( 'pid' ) ;
89+
8790 pidControl ?. setValue ( 'invalid-doi' ) ;
8891 pidControl ?. updateValueAndValidity ( ) ;
8992
@@ -92,53 +95,130 @@ describe('AddResourceDialogComponent', () => {
9295 } ) ;
9396
9497 it ( 'should accept valid DOI format' , ( ) => {
98+ const { component } = setup ( ) ;
9599 const pidControl = component . form . get ( 'pid' ) ;
100+
96101 pidControl ?. setValue ( '10.1234/valid.doi' ) ;
97102
98103 expect ( pidControl ?. hasError ( 'doi' ) ) . toBe ( false ) ;
99104 } ) ;
100105
101106 it ( 'should not preview resource when form is invalid' , ( ) => {
102- const dispatchSpy = jest . spyOn ( store , 'dispatch' ) ;
103- component . form . get ( 'pid' ) ?. setValue ( '' ) ;
107+ const { component, store } = setup ( ) ;
108+
109+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
110+ component . previewResource ( ) ;
111+
112+ expect ( store . dispatch ) . not . toHaveBeenCalled ( ) ;
113+ expect ( component . isPreviewMode ( ) ) . toBe ( false ) ;
114+ } ) ;
115+
116+ it ( 'should not preview resource when currentResource is null' , ( ) => {
117+ const { component, store } = setup ( ) ;
104118
119+ component . form . patchValue ( { pid : '10.1234/test' , resourceType : 'data' } ) ;
120+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
105121 component . previewResource ( ) ;
106122
107- expect ( dispatchSpy ) . not . toHaveBeenCalled ( ) ;
123+ expect ( store . dispatch ) . not . toHaveBeenCalled ( ) ;
108124 expect ( component . isPreviewMode ( ) ) . toBe ( false ) ;
109125 } ) ;
110126
111- it ( 'should throw error when previewing resource without current resource' , ( ) => {
112- component . form . patchValue ( {
113- pid : '10.1234/test' ,
114- resourceType : 'dataset' ,
127+ it ( 'should preview resource and set preview mode on success' , ( ) => {
128+ const { component, store } = setup ( {
129+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : MOCK_RESOURCE } ] ,
115130 } ) ;
116131
117- expect ( ( ) => component . previewResource ( ) ) . toThrow ( ) ;
132+ component . form . patchValue ( { pid : '10.1234/test' , resourceType : 'data' , description : 'desc' } ) ;
133+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
134+ component . previewResource ( ) ;
135+
136+ expect ( store . dispatch ) . toHaveBeenCalled ( ) ;
137+ expect ( component . isPreviewMode ( ) ) . toBe ( true ) ;
118138 } ) ;
119139
120140 it ( 'should set isPreviewMode to false when backToEdit is called' , ( ) => {
121- component . isPreviewMode . set ( true ) ;
141+ const { component } = setup ( ) ;
122142
143+ component . isPreviewMode . set ( true ) ;
123144 component . backToEdit ( ) ;
124145
125146 expect ( component . isPreviewMode ( ) ) . toBe ( false ) ;
126147 } ) ;
127148
128- it ( 'should throw error when adding resource without current resource' , ( ) => {
129- expect ( ( ) => component . onAddResource ( ) ) . toThrow ( ) ;
149+ it ( 'should not add resource when currentResource is null' , ( ) => {
150+ const { component, store, dialogRef } = setup ( ) ;
151+
152+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
153+ component . onAddResource ( ) ;
154+
155+ expect ( store . dispatch ) . not . toHaveBeenCalled ( ) ;
156+ expect ( dialogRef . close ) . not . toHaveBeenCalled ( ) ;
130157 } ) ;
131158
132- it ( 'should close dialog without deleting when closeDialog is called without current resource' , ( ) => {
133- const dispatchSpy = jest . spyOn ( store , 'dispatch' ) ;
159+ it ( 'should confirm add resource and close dialog on success' , ( ) => {
160+ const { component, store, dialogRef } = setup ( {
161+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : MOCK_RESOURCE } ] ,
162+ } ) ;
163+
164+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
165+ component . onAddResource ( ) ;
134166
167+ expect ( component . isResourceConfirming ( ) ) . toBe ( false ) ;
168+ expect ( store . dispatch ) . toHaveBeenCalled ( ) ;
169+ expect ( dialogRef . close ) . toHaveBeenCalledWith ( true ) ;
170+ } ) ;
171+
172+ it ( 'should close dialog without deleting when currentResource is null' , ( ) => {
173+ const { component, store, dialogRef } = setup ( ) ;
174+
175+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
176+ component . closeDialog ( ) ;
177+
178+ expect ( dialogRef . close ) . toHaveBeenCalled ( ) ;
179+ expect ( store . dispatch ) . not . toHaveBeenCalled ( ) ;
180+ } ) ;
181+
182+ it ( 'should delete resource and close dialog when currentResource exists' , ( ) => {
183+ const { component, store, dialogRef } = setup ( {
184+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : MOCK_RESOURCE } ] ,
185+ } ) ;
186+
187+ ( store . dispatch as jest . Mock ) . mockClear ( ) ;
135188 component . closeDialog ( ) ;
136189
190+ expect ( store . dispatch ) . toHaveBeenCalled ( ) ;
137191 expect ( dialogRef . close ) . toHaveBeenCalled ( ) ;
138- expect ( dispatchSpy ) . not . toHaveBeenCalled ( ) ;
139192 } ) ;
140193
141- it ( 'should compute doiLink as undefined when current resource does not exist' , ( ) => {
142- expect ( component . doiLink ( ) ) . toBe ( 'https://doi.org/undefined' ) ;
194+ it ( 'should compute doiLink from currentResource pid' , ( ) => {
195+ const { component } = setup ( {
196+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : MOCK_RESOURCE } ] ,
197+ } ) ;
198+
199+ expect ( component . doiLink ( ) ) . toBe ( 'https://doi.org/10.1234/test' ) ;
200+ } ) ;
201+
202+ it ( 'should return empty string for resourceTypeTranslationKey when currentResource is null' , ( ) => {
203+ const { component } = setup ( ) ;
204+
205+ expect ( component . resourceTypeTranslationKey ( ) ) . toBe ( '' ) ;
206+ } ) ;
207+
208+ it ( 'should return translation key for resourceTypeTranslationKey when resource type matches' , ( ) => {
209+ const { component } = setup ( {
210+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : MOCK_RESOURCE } ] ,
211+ } ) ;
212+
213+ expect ( component . resourceTypeTranslationKey ( ) ) . toBe ( 'resources.typeOptions.data' ) ;
214+ } ) ;
215+
216+ it ( 'should return empty string for resourceTypeTranslationKey when type is unknown' , ( ) => {
217+ const unknownResource = { ...MOCK_RESOURCE , type : 'unknown_type' as RegistryResourceType } ;
218+ const { component } = setup ( {
219+ selectorOverrides : [ { selector : RegistryResourcesSelectors . getCurrentResource , value : unknownResource } ] ,
220+ } ) ;
221+
222+ expect ( component . resourceTypeTranslationKey ( ) ) . toBe ( '' ) ;
143223 } ) ;
144224} ) ;
0 commit comments