chore(integration): snapshot local main worktree

This commit is contained in:
inman
2026-08-31 10:23:21 +08:00
parent 48a9189939
commit 33fb31fb28
116 changed files with 8108 additions and 3026 deletions

View File

@@ -43,6 +43,22 @@ describe('auth store', () => {
vi.useRealTimers();
});
it('does not treat an orphaned access token as an authenticated identity', async () => {
useAuthStore.setState({
initialized: true,
accessToken: 'orphaned-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
user: null,
});
expect(useAuthStore.getState().isAuthenticated()).toBe(false);
await expect(useAuthStore.getState().getValidAccessToken()).resolves.toBeNull();
expect(hostApiFetchMock).not.toHaveBeenCalled();
});
it('logs in with a password through the host api and stores the hydrated session', async () => {
hostApiFetchMock
.mockResolvedValueOnce({
@@ -250,6 +266,137 @@ describe('auth store', () => {
});
});
it('rehydrates a missing persisted identity from the current-user projection', async () => {
hostApiFetchMock
.mockResolvedValueOnce({
success: true,
session: {
accessToken: 'persisted-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
},
})
.mockResolvedValueOnce({
success: true,
user: {
username: 'restored-user',
userId: '42',
tenantId: 7,
deptId: 'engineering',
authorities: ['ROLE_USER'],
},
moduleAccess: { design: false },
});
useAuthStore.setState({
authBase: 'https://biz.nianxx.cn/auth/',
accessToken: 'persisted-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
user: null,
});
await useAuthStore.getState().init();
expect(useAuthStore.getState()).toMatchObject({
initialized: true,
loading: false,
error: null,
user: {
username: 'restored-user',
userId: '42',
tenantId: 7,
deptId: 'engineering',
authorities: ['ROLE_USER'],
},
moduleAccess: {
programming: true,
design: false,
learning: true,
robot: true,
},
});
expect(useAuthStore.getState().isAuthenticated()).toBe(true);
});
it('clears a synchronized session when no user identity can be recovered', async () => {
hostApiFetchMock
.mockResolvedValueOnce({
success: true,
session: {
accessToken: 'orphaned-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
},
})
.mockResolvedValueOnce({
success: true,
moduleAccess: { programming: true },
})
.mockResolvedValueOnce({ success: true });
useAuthStore.setState({
authBase: 'https://biz.nianxx.cn/auth/',
accessToken: 'orphaned-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
user: null,
});
await useAuthStore.getState().init();
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
3,
'/api/auth/session/clear',
{ method: 'POST' },
);
expect(useAuthStore.getState()).toMatchObject({
initialized: true,
loading: false,
error: '登录身份无法确认,请重新登录。',
accessToken: null,
user: null,
canRefresh: false,
});
expect(useAuthStore.getState().isAuthenticated()).toBe(false);
});
it('fails closed when session sync is unavailable and only an orphaned token was persisted', async () => {
hostApiFetchMock
.mockRejectedValueOnce(new Error('Host API unavailable'))
.mockResolvedValueOnce({ success: true });
useAuthStore.setState({
authBase: 'https://biz.nianxx.cn/auth/',
accessToken: 'orphaned-access-token',
tokenType: 'Bearer',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
canRefresh: true,
user: null,
});
await useAuthStore.getState().init();
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
2,
'/api/auth/session/clear',
{ method: 'POST' },
);
expect(useAuthStore.getState()).toMatchObject({
initialized: true,
loading: false,
error: '登录身份无法确认,请重新登录。',
accessToken: null,
user: null,
});
});
it('clears restored auth when the current-user policy lookup is unauthorized', async () => {
hostApiFetchMock
.mockResolvedValueOnce({
@@ -939,6 +1086,13 @@ describe('auth store', () => {
lastActiveAt: Date.now(),
canRefresh: true,
legacyRefreshToken: null,
user: {
username: 'zhangsan',
userId: '1',
tenantId: null,
deptId: null,
authorities: [],
},
});
await expect(useAuthStore.getState().refreshSession()).resolves.toBe('new-access-token');
@@ -970,6 +1124,13 @@ describe('auth store', () => {
lastActiveAt,
canRefresh: true,
legacyRefreshToken: null,
user: {
username: 'zhangsan',
userId: '1',
tenantId: null,
deptId: null,
authorities: [],
},
});
await useAuthStore.getState().maintainSession();