diff --git a/frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js b/frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js index d81981e..70851c3 100644 --- a/frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js +++ b/frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js @@ -39,19 +39,42 @@ const mockSetBrowseState = vi.fn() const mockSelectConnection = vi.fn() const mockFetchConnections = vi.fn().mockResolvedValue(undefined) +/** + * Reactive mock store state — must use Vue refs so that CloudFolderView's + * template reactivity (`:folder-freshness="cloudStore.folderFreshness"`) picks + * up changes when setBrowseState is called during the browse cycle (D-12/D-13). + */ +import { ref } from 'vue' + +const _mockFolderFreshness = ref(null) +const _mockLastRefreshedAt = ref(null) +const _mockCapabilities = ref(null) +const _mockByteAvailability = ref(null) + vi.mock('../../stores/cloudConnections.js', () => ({ useCloudConnectionsStore: () => ({ connections: [ { id: 'conn-rendered-1', provider: 'webdav', display_name: 'Test WebDAV' }, ], loading: false, - capabilities: null, - folderFreshness: null, - lastRefreshedAt: null, - byteAvailability: null, + get capabilities() { return _mockCapabilities.value }, + get folderFreshness() { return _mockFolderFreshness.value }, + get lastRefreshedAt() { return _mockLastRefreshedAt.value }, + get byteAvailability() { return _mockByteAvailability.value }, fetchConnections: mockFetchConnections, selectConnection: mockSelectConnection, - setBrowseState: mockSetBrowseState, + /** + * D-12: setBrowseState must update reactive folderFreshness so CloudFolderView + * propagates it to StorageBrowser as a prop. Without reactivity, the health + * banner never appears (T-13-30 mitigated here in GREEN). + */ + setBrowseState(payload) { + mockSetBrowseState(payload) + if (payload.freshness !== undefined) _mockFolderFreshness.value = payload.freshness + if (payload.refreshedAt !== undefined) _mockLastRefreshedAt.value = payload.refreshedAt + if (payload.caps !== undefined) _mockCapabilities.value = payload.caps + if (payload.byteAvail !== undefined) _mockByteAvailability.value = payload.byteAvail + }, defaultDisplayName: (c) => c.provider, }), saveLastFolder: vi.fn(), @@ -63,10 +86,16 @@ vi.mock('../../stores/toast.js', () => ({ })) // Network boundary: stub only the API layer +// D-13: testCloudConnection must be defined in mock so no-probe-on-navigation +// tests can assert it was NOT called during ordinary folder browse (T-13-30). vi.mock('../../api/client.js', () => ({ getCloudFoldersByConnectionId: vi.fn().mockResolvedValue({ items: [], capabilities: null }), uploadToCloud: vi.fn(), listCloudConnections: vi.fn().mockResolvedValue({ items: [] }), + testCloudConnection: vi.fn(), + openCloudFile: vi.fn(), + downloadCloudFile: vi.fn(), + uploadCloudFile: vi.fn(), })) import CloudFolderView from '../CloudFolderView.vue' @@ -161,6 +190,11 @@ beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() sessionStorage.clear() + // Reset reactive mock store state between tests (D-12 health state isolation) + _mockFolderFreshness.value = null + _mockLastRefreshedAt.value = null + _mockCapabilities.value = null + _mockByteAvailability.value = null }) afterEach(() => {