@@ -4,7 +4,7 @@ import { DialogService } from 'primeng/dynamicdialog';
44
55import { signal } from '@angular/core' ;
66import { ComponentFixture , TestBed } from '@angular/core/testing' ;
7- import { ActivatedRoute } from '@angular/router' ;
7+ import { ActivatedRoute , Router } from '@angular/router' ;
88
99import { SENTRY_TOKEN } from '@core/provider/sentry.provider' ;
1010import { FileUploadDialogComponent } from '@osf/shared/components/file-upload-dialog/file-upload-dialog.component' ;
@@ -18,8 +18,10 @@ import { CustomConfirmationService } from '@osf/shared/services/custom-confirmat
1818import { FilesService } from '@osf/shared/services/files.service' ;
1919import { CurrentResourceSelectors } from '@osf/shared/stores/current-resource' ;
2020import { GoogleFilePickerComponent } from '@shared/components/google-file-picker/google-file-picker.component' ;
21+ import { FileLabelModel } from '@shared/models/files/file-label.model' ;
2122
2223import { FilesSelectionActionsComponent } from '../../components' ;
24+ import { FileProvider } from '../../constants' ;
2325import { FilesSelectors } from '../../store' ;
2426
2527import { FilesComponent } from './files.component' ;
@@ -29,6 +31,8 @@ import { getNodeFilesMappedData } from '@testing/data/files/node.data';
2931import { testNode } from '@testing/mocks/base-node.mock' ;
3032import { OSFTestingModule } from '@testing/osf.testing.module' ;
3133import { MockComponentWithSignal } from '@testing/providers/component-provider.mock' ;
34+ import { ActivatedRouteMock } from '@testing/providers/route-provider.mock' ;
35+ import { provideRouterMock , RouterMockType } from '@testing/providers/router-provider.mock' ;
3236import { provideMockStore } from '@testing/providers/store-provider.mock' ;
3337
3438describe ( 'Component: Files' , ( ) => {
@@ -188,4 +192,138 @@ describe('Component: Files', () => {
188192 expect ( ( ) => component . updateFilesList ( ) ) . not . toThrow ( ) ;
189193 } ) ;
190194 } ) ;
195+
196+ describe ( 'handleRootFolderChange' , ( ) => {
197+ it ( 'should preserve view_only query param when switching storage providers' , ( ) => {
198+ const router = TestBed . inject ( Router ) ;
199+ const navigateSpy = jest . spyOn ( router , 'navigate' ) . mockResolvedValue ( true ) ;
200+
201+ const selectedFolder : FileLabelModel = {
202+ label : 'Dropbox' ,
203+ folder : { provider : FileProvider . Dropbox } as any ,
204+ } ;
205+
206+ component . handleRootFolderChange ( selectedFolder ) ;
207+
208+ expect ( navigateSpy ) . toHaveBeenCalledWith ( [ `/${ component . resourceId ( ) } /files` , FileProvider . Dropbox ] , {
209+ queryParamsHandling : 'preserve' ,
210+ } ) ;
211+ } ) ;
212+ } ) ;
213+
214+ describe ( 'invalid provider fallback effect' , ( ) => {
215+ let innerComponent : FilesComponent ;
216+ let innerFixture : ComponentFixture < FilesComponent > ;
217+ let routerMock : RouterMockType ;
218+
219+ beforeEach ( async ( ) => {
220+ jest . clearAllMocks ( ) ;
221+ routerMock = {
222+ ...TestBed . inject ( Router ) ,
223+ navigate : jest . fn ( ) . mockResolvedValue ( true ) ,
224+ url : '/abc123/files/unknownprovider?view_only=testtoken' ,
225+ } as RouterMockType ;
226+
227+ await TestBed . configureTestingModule ( {
228+ imports : [
229+ FilesComponent ,
230+ OSFTestingModule ,
231+ ...MockComponents (
232+ FileUploadDialogComponent ,
233+ FormSelectComponent ,
234+ GoogleFilePickerComponent ,
235+ LoadingSpinnerComponent ,
236+ SearchInputComponent ,
237+ SubHeaderComponent ,
238+ ViewOnlyLinkMessageComponent ,
239+ GoogleFilePickerComponent ,
240+ FilesSelectionActionsComponent
241+ ) ,
242+ ] ,
243+ providers : [
244+ FilesService ,
245+ MockProvider ( CustomConfirmationService ) ,
246+ DialogService ,
247+ {
248+ provide : SENTRY_TOKEN ,
249+ useValue : {
250+ captureException : jest . fn ( ) ,
251+ captureMessage : jest . fn ( ) ,
252+ setUser : jest . fn ( ) ,
253+ } ,
254+ } ,
255+ {
256+ provide : ActivatedRoute ,
257+ useValue : ActivatedRouteMock . withParams ( { fileProvider : 'unknownprovider' } ) . build ( ) ,
258+ } ,
259+ provideRouterMock ( routerMock ) ,
260+ provideMockStore ( {
261+ signals : [
262+ {
263+ selector : CurrentResourceSelectors . getResourceDetails ,
264+ value : testNode ,
265+ } ,
266+ {
267+ selector : FilesSelectors . getRootFolders ,
268+ value : getNodeFilesMappedData ( ) ,
269+ } ,
270+ {
271+ selector : FilesSelectors . getCurrentFolder ,
272+ value : getNodeFilesMappedData ( 0 ) ,
273+ } ,
274+ {
275+ selector : FilesSelectors . getConfiguredStorageAddons ,
276+ value : getConfiguredAddonsMappedData ( ) ,
277+ } ,
278+ {
279+ selector : FilesSelectors . getProvider ,
280+ value : 'osfstorage' ,
281+ } ,
282+ {
283+ selector : FilesSelectors . getStorageSupportedFeatures ,
284+ value : {
285+ osfstorage : [ 'AddUpdateFiles' , 'DownloadAsZip' , 'DeleteFiles' , 'CopyInto' ] ,
286+ } ,
287+ } ,
288+ ] ,
289+ } ) ,
290+ ] ,
291+ } )
292+ . overrideComponent ( FilesComponent , {
293+ remove : {
294+ imports : [ FilesTreeComponent ] ,
295+ } ,
296+ add : {
297+ imports : [
298+ MockComponentWithSignal ( 'osf-files-tree' , [
299+ 'files' ,
300+ 'currentFolder' ,
301+ 'isLoading' ,
302+ 'viewOnly' ,
303+ 'resourceId' ,
304+ 'provider' ,
305+ 'storage' ,
306+ 'totalCount' ,
307+ 'allowedMenuActions' ,
308+ 'supportUpload' ,
309+ 'selectedFiles' ,
310+ 'scrollHeight' ,
311+ ] ) ,
312+ ] ,
313+ } ,
314+ } )
315+ . compileComponents ( ) ;
316+
317+ innerFixture = TestBed . createComponent ( FilesComponent ) ;
318+ innerComponent = innerFixture . componentInstance ;
319+ innerFixture . detectChanges ( ) ;
320+ } ) ;
321+
322+ it ( 'should preserve view_only query param when redirecting to osfstorage for invalid provider' , ( ) => {
323+ expect ( routerMock . navigate ) . toHaveBeenCalledWith (
324+ [ `/${ innerComponent . resourceId ( ) } /files` , FileProvider . OsfStorage ] ,
325+ { queryParamsHandling : 'preserve' }
326+ ) ;
327+ } ) ;
328+ } ) ;
191329} ) ;
0 commit comments