为处理中、失败和清理中的配对展示明确状态与恢复动作,支持放弃并清理、作用域内退役冲突连接,并在 Active 状态引导管理员先安全禁用再使用新接入码。同步修复运行时切换后的浏览器会话残留与确认弹窗焦点约束。 验证:pnpm test;pnpm lint;pnpm build。
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { OIDC_BROWSER_SESSION_CREDENTIAL } from '../api';
|
|
import {
|
|
reconcileOIDCBrowserSessionAfterRuntimeChange,
|
|
restoreOIDCBrowserSession,
|
|
} from './oidc-browser-session';
|
|
|
|
describe('OIDC browser session lifecycle', () => {
|
|
it('restores a shared cookie session in a fresh tab', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
|
|
sub: 'platform-user', source: 'oidc', gatewayUserId: 'gateway-user',
|
|
}), { status: 200, headers: { 'Content-Type': 'application/json' } })));
|
|
|
|
const restored = await restoreOIDCBrowserSession();
|
|
|
|
expect(restored?.credential).toBe(OIDC_BROWSER_SESSION_CREDENTIAL);
|
|
expect(restored?.user.sub).toBe('platform-user');
|
|
});
|
|
|
|
it('treats a missing or expired shared cookie as a signed-out tab', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
|
|
error: { message: 'unauthorized', status: 401 },
|
|
}), { status: 401, headers: { 'Content-Type': 'application/json' } })));
|
|
|
|
await expect(restoreOIDCBrowserSession()).resolves.toBeNull();
|
|
});
|
|
|
|
it('resets App authentication when an OIDC sentinel session re-probe returns 401', async () => {
|
|
const resetAuthenticatedSession = vi.fn();
|
|
const onRestored = vi.fn();
|
|
const fetchMock = vi.fn().mockResolvedValue(new Response(JSON.stringify({
|
|
error: { message: 'unauthorized', status: 401 },
|
|
}), { status: 401, headers: { 'Content-Type': 'application/json' } }));
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
|
|
await expect(reconcileOIDCBrowserSessionAfterRuntimeChange({
|
|
credential: OIDC_BROWSER_SESSION_CREDENTIAL,
|
|
oidcEnabled: true,
|
|
onReset: resetAuthenticatedSession,
|
|
onRestored,
|
|
})).resolves.toBe('reset');
|
|
|
|
expect(fetchMock).toHaveBeenCalledOnce();
|
|
expect(resetAuthenticatedSession).toHaveBeenCalledOnce();
|
|
expect(onRestored).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('resets App authentication without probing /me when identity is disabled', async () => {
|
|
const resetAuthenticatedSession = vi.fn();
|
|
const onRestored = vi.fn();
|
|
const fetchMock = vi.fn();
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
|
|
await expect(reconcileOIDCBrowserSessionAfterRuntimeChange({
|
|
credential: OIDC_BROWSER_SESSION_CREDENTIAL,
|
|
oidcEnabled: false,
|
|
onReset: resetAuthenticatedSession,
|
|
onRestored,
|
|
})).resolves.toBe('reset');
|
|
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
expect(resetAuthenticatedSession).toHaveBeenCalledOnce();
|
|
expect(onRestored).not.toHaveBeenCalled();
|
|
});
|
|
});
|