Show a login notice when a session ends due to idle timeout.

Return a distinct session_idle error from the API and reload to /login with a clear signed-out message.
This commit is contained in:
2026-07-18 20:50:52 +02:00
parent c90a47c3ea
commit e3793f380c
9 changed files with 353 additions and 3 deletions
+69
View File
@@ -14,6 +14,7 @@ import {
fetchStatus,
fetchUsers,
getApiBaseUrl,
login,
patchAction,
saveNetwork,
saveSecurity,
@@ -716,3 +717,71 @@ describe('actions API', () => {
)
})
})
describe('session idle redirect', () => {
afterEach(() => {
vi.restoreAllMocks()
})
it('reloads to login when an authenticated call returns session_idle', async () => {
const assign = vi.fn()
vi.stubGlobal('location', {
pathname: '/configuration/security',
assign,
})
const fetchMock = vi.fn().mockResolvedValue({
ok: false,
status: 401,
clone: () => ({
json: async () => ({ error: 'session_idle' }),
}),
json: async () => ({ error: 'session_idle' }),
})
await expect(fetchStatus(fetchMock)).rejects.toThrow()
expect(assign).toHaveBeenCalledWith('/login?reason=idle')
})
it('does not redirect on login 401', async () => {
const assign = vi.fn()
vi.stubGlobal('location', {
pathname: '/login',
assign,
})
const fetchMock = vi.fn().mockResolvedValue({
ok: false,
status: 401,
clone: () => ({
json: async () => ({ error: 'invalid credentials' }),
}),
json: async () => ({ error: 'invalid credentials' }),
})
await expect(login('Admin', 'wrong', '', fetchMock)).rejects.toThrow(
'invalid credentials',
)
expect(assign).not.toHaveBeenCalled()
})
it('does not redirect for generic authentication required', async () => {
const assign = vi.fn()
vi.stubGlobal('location', {
pathname: '/',
assign,
})
const fetchMock = vi.fn().mockResolvedValue({
ok: false,
status: 401,
clone: () => ({
json: async () => ({ error: 'authentication required' }),
}),
json: async () => ({ error: 'authentication required' }),
})
await expect(fetchStatus(fetchMock)).rejects.toThrow()
expect(assign).not.toHaveBeenCalled()
})
})