diff --git a/apps/web/src/hooks/useFolderNavigation.ts b/apps/web/src/hooks/useFolderNavigation.ts index 36b8f26a67..a5c10eea52 100644 --- a/apps/web/src/hooks/useFolderNavigation.ts +++ b/apps/web/src/hooks/useFolderNavigation.ts @@ -267,8 +267,17 @@ export function useFolderNavigation(): UseFolderNavigationReturn { console.error('Failed to load subfolder:', err); // Only clean up if this is still the latest navigation if (latestNavTarget.current !== targetFolderId) return; - // Remove the loading placeholder so the user can retry + // Remove the loading placeholder and navigate back to parent. + // Without this navigation, the URL stays at /files/ with no + // folder in the store, rendering a broken empty ~/root fallback. useFolderStore.getState().removeFolder(targetFolderId); + setIsLoading(false); + latestNavTarget.current = parentId ?? 'root'; + if (parentId) { + navigate(`/files/${parentId}`); + } else { + navigate('/files'); + } } finally { // Only clear loading if this is still the latest navigation if (latestNavTarget.current === targetFolderId) { diff --git a/tests/e2e/tests/full-workflow.spec.ts b/tests/e2e/tests/full-workflow.spec.ts index 3fa94fe2d3..e3cb8cea3d 100644 --- a/tests/e2e/tests/full-workflow.spec.ts +++ b/tests/e2e/tests/full-workflow.spec.ts @@ -174,11 +174,23 @@ test.describe.serial('Full Workflow', () => { * Phase 6.3: Uses breadcrumb path to verify navigation (~/root/foldername format). */ async function navigateIntoFolder(name: string): Promise { - await fileList.doubleClickFolder(name); - // Wait for breadcrumb path to include the folder name. - // Post-reload navigation requires cold IPNS resolve which can be slow in CI. - await breadcrumbs.waitForPathToContain(name, { timeout: 30000 }); - navigationStack.push(name); + // Retry once if navigation fails (transient IPNS resolution failures in CI + // cause the app to navigate back to parent; the folder row reappears and + // a second attempt usually succeeds). + for (let attempt = 0; attempt < 2; attempt++) { + await fileList.doubleClickFolder(name); + try { + await breadcrumbs.waitForPathToContain(name, { timeout: 30000 }); + navigationStack.push(name); + return; + } catch { + if (attempt === 1) throw new Error(`navigateIntoFolder("${name}") failed after 2 attempts`); + // Wait for the app to settle after a failed navigation (it navigates back to parent) + await page.waitForTimeout(2000); + // Verify the folder row is still visible before retrying + await fileList.waitForItemToAppear(name, { timeout: 10000 }); + } + } } /**