M5: roll Energy chart window for live auto-refresh (English label); render boolean config fields as switches

This commit is contained in:
2026-06-22 19:40:18 +02:00
parent 935e68846c
commit 75d685f04d
10 changed files with 468 additions and 30 deletions
+74
View File
@@ -418,4 +418,78 @@ describe('useReadings', () => {
}),
)
})
// -------------------------------------------------------------------------
// Rolling window: spanMs causes queryFn to compute end=now() on each call
// -------------------------------------------------------------------------
it('when spanMs is provided, sends computed start/end (rolling window) instead of fixed params', async () => {
const tBefore = Date.now()
mockGet.mockResolvedValue({ data: { items: [] } })
const { Wrapper } = makeWrapper()
const { useReadings } = await import('./hooks')
const SPAN_MS = 60 * 60 * 1000 // 1 hour
const { result } = renderHook(
() => useReadings('test-uuid-1', { spanMs: SPAN_MS }),
{ wrapper: Wrapper },
)
await waitFor(() => expect(result.current.isSuccess).toBe(true))
const tAfter = Date.now()
// The GET should have been called with start and end computed from now().
expect(mockGet).toHaveBeenCalledWith(
'/api/modbus/devices/{uuid}/readings',
expect.objectContaining({
params: expect.objectContaining({
query: expect.objectContaining({
end: expect.any(String),
start: expect.any(String),
}),
}),
}),
)
const call = mockGet.mock.calls[mockGet.mock.calls.length - 1]
const query = call[1].params.query as { start: string; end: string }
const endMs = new Date(query.end).getTime()
const startMs = new Date(query.start).getTime()
// end must be within the test window (tBefore..tAfter).
expect(endMs).toBeGreaterThanOrEqual(tBefore)
expect(endMs).toBeLessThanOrEqual(tAfter + 100) // small tolerance
// start must be approximately end - spanMs.
expect(endMs - startMs).toBeCloseTo(SPAN_MS, -2) // within 100ms
})
it('when spanMs is provided, queryKey uses spanMs (not absolute timestamps) for stable caching', async () => {
mockGet.mockResolvedValue({ data: { items: [] } })
const { Wrapper, qc } = makeWrapper()
const { useReadings } = await import('./hooks')
const SPAN_MS = 3600000 // 1 hour
const { result } = renderHook(
() => useReadings('test-uuid-1', { spanMs: SPAN_MS }),
{ wrapper: Wrapper },
)
await waitFor(() => expect(result.current.isSuccess).toBe(true))
// The query cache should have a key containing spanMs, not an absolute timestamp.
const queries = qc.getQueryCache().findAll({
predicate: (q) => {
const key = q.queryKey as unknown[]
return key[0] === 'modbus-readings' && key[1] === 'test-uuid-1'
},
})
expect(queries).toHaveLength(1)
const keyParams = queries[0].queryKey[2] as Record<string, unknown>
expect(keyParams).toHaveProperty('spanMs', SPAN_MS)
expect(keyParams).not.toHaveProperty('start')
expect(keyParams).not.toHaveProperty('end')
})
})