test(12.1-03): add RED tests for server freshness mapping

- cloudConnections: setBrowseState warning/refreshing/fresh states
- cloudConnections: cached items remain during warning
- cloudConnections: selectConnection clears browse state
- cloudConnections: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: maps_server_warning_and_last_success
- CloudFolderView: http_200_does_not_imply_fresh
- CloudFolderView: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: cached_items_remain_visible_during_warning
3 new failures against unconditional fresh/new Date() behavior
This commit is contained in:
curo1305
2026-06-22 08:45:50 +02:00
parent ba7f652cde
commit 9974fca2cb
2 changed files with 194 additions and 0 deletions
@@ -306,3 +306,117 @@ describe('opaque_reference_round_trip', () => {
}
})
})
// ── Freshness mapping: server state is authoritative ─────────────────────────
describe('maps_server_refreshing_freshness', () => {
it('setBrowseState is called with refreshing before the API resolves', async () => {
// Make the API resolve async so we can check the in-flight state
let resolveApi
api.getCloudFoldersByConnectionId.mockReturnValue(new Promise(r => { resolveApi = r }))
const w = mount(CloudFolderView, { global: { stubs: globalStubs } })
// Before resolution: refreshing must have been set
expect(mockSetBrowseState).toHaveBeenCalledWith(expect.objectContaining({ freshness: 'refreshing' }))
// Complete the request
resolveApi({
items: [],
capabilities: null,
freshness: { refresh_state: 'fresh', last_refreshed_at: '2026-06-22T00:00:00Z' },
})
await flushPromises()
})
})
describe('maps_server_warning_and_last_success', () => {
it('HTTP 200 with warning freshness calls setBrowseState with warning, not fresh', async () => {
const SERVER_TS = '2026-06-10T12:00:00.000Z'
api.getCloudFoldersByConnectionId.mockResolvedValue({
items: [FOLDER_A],
capabilities: null,
freshness: {
refresh_state: 'warning',
last_refreshed_at: SERVER_TS,
error_code: 'incomplete_listing',
error_message: 'Provider returned incomplete results.',
},
})
const w = mount(CloudFolderView, { global: { stubs: globalStubs } })
await flushPromises()
// setBrowseState must be called with freshness='warning', NOT 'fresh'
const calls = mockSetBrowseState.mock.calls
const finalCall = calls.find(c => c[0].freshness === 'warning')
expect(finalCall).toBeDefined()
// fresh must NOT be set after a warning response
const freshCall = calls.find(c => c[0].freshness === 'fresh')
expect(freshCall).toBeUndefined()
})
})
describe('http_200_does_not_imply_fresh', () => {
it('HTTP 200 with warning state does not result in fresh freshness being set', async () => {
api.getCloudFoldersByConnectionId.mockResolvedValue({
items: [],
capabilities: null,
freshness: {
refresh_state: 'warning',
last_refreshed_at: null,
error_code: 'incomplete_listing',
error_message: null,
},
})
const w = mount(CloudFolderView, { global: { stubs: globalStubs } })
await flushPromises()
// None of the setBrowseState calls (excluding the initial 'refreshing') should set 'fresh'
const freshAfterLoad = mockSetBrowseState.mock.calls
.filter(c => c[0].freshness === 'fresh')
expect(freshAfterLoad.length).toBe(0)
})
})
describe('does_not_use_browser_clock_as_refresh_evidence', () => {
it('refreshedAt passed to setBrowseState comes from server last_refreshed_at, not new Date()', async () => {
const SERVER_TS = '2026-06-01T08:00:00.000Z'
api.getCloudFoldersByConnectionId.mockResolvedValue({
items: [],
capabilities: null,
freshness: {
refresh_state: 'fresh',
last_refreshed_at: SERVER_TS,
},
})
const w = mount(CloudFolderView, { global: { stubs: globalStubs } })
await flushPromises()
// Find the setBrowseState call that carries a refreshedAt
const calls = mockSetBrowseState.mock.calls
const callWithTs = calls.find(c => c[0].refreshedAt !== undefined && c[0].refreshedAt !== null)
expect(callWithTs).toBeDefined()
// The timestamp must be exactly what the server sent
expect(callWithTs[0].refreshedAt).toBe(SERVER_TS)
// Must NOT contain 'Z' as a result of new Date().toISOString() producing a different value
// (if the test is run quickly, these might match by coincidence — but the semantic check is:
// does the code use the server value or call new Date()?)
// We verify this by checking the value matches the exact server string, not a generated one
expect(callWithTs[0].refreshedAt).not.toMatch(/^2026-06-22/) // not today's date
})
})
describe('cached_items_remain_visible_during_warning', () => {
it('on HTTP 200 warning, items from response are still passed to store', async () => {
api.getCloudFoldersByConnectionId.mockResolvedValue({
items: [FOLDER_A, FILE_A],
capabilities: null,
freshness: {
refresh_state: 'warning',
last_refreshed_at: '2026-06-01T00:00:00Z',
error_code: 'incomplete_listing',
error_message: null,
},
})
const w = mount(CloudFolderView, { global: { stubs: globalStubs } })
await flushPromises()
// Items must be passed to the store even during a warning state
const callWithItems = mockSetBrowseState.mock.calls.find(c => c[0].items !== undefined)
expect(callWithItems).toBeDefined()
expect(callWithItems[0].items.length).toBe(2)
})
})