From a7e55d1bb0ea4e3e34514cb0993685e16f9f312d Mon Sep 17 00:00:00 2001 From: curo1305 Date: Mon, 22 Jun 2026 23:56:13 +0200 Subject: [PATCH] feat(13-10): reactive mock store in rendered-flow test surfaces health banner and no-probe assertions - CloudFolderRenderedFlow.test.js: mock store uses Vue refs so folderFreshness propagates reactively to StorageBrowser via CloudFolderView's template binding (D-12 GREEN) - setBrowseState in mock now updates _mockFolderFreshness so cloud-health-banner appears when API returns warning freshness (T-13-30 mitigated) - Added testCloudConnection to API mock so D-13 no-probe assertion can verify it was not called - beforeEach resets reactive refs for test isolation - 11 rendered-flow tests pass; 70 total across health/store/view/rendered-flow suites --- .../__tests__/CloudFolderRenderedFlow.test.js | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) 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(() => {