From 0ebb2b86bdfb6db465f6d4a4a9657fc2d58131ac Mon Sep 17 00:00:00 2001 From: opsx Date: Tue, 3 Nov 2026 03:26:45 +0000 Subject: [PATCH] =?UTF-8?q?test(auth):=20=E9=94=81=E4=BD=8F"=E5=B7=B2?= =?UTF-8?q?=E5=9C=A8=20/login=20=E6=97=B6=20401=20=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E9=87=8D=E8=BD=BD"=E7=9A=84=E5=9B=9E=E5=BD=92=EF=BC=88?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=A1=B5=E6=AD=BB=E5=BE=AA=E7=8E=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补一条前端单测:处于 /login 且无 refreshToken 时发起鉴权请求 → 401 → 不得重新赋值 window.location.href。 背景:redirectToLogin 曾对已在 /login 的情况也赋值 href='/login', 赋同值同样触发整页重载 → App 重新挂载 → LicenseProvider 再请求 → 再 401 → 再重载,形成死循环(线上 10 分钟 1566 次 401、登录页闪屏)。 vitest: 4 个用例全绿。 --- frontend/src/api/http.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frontend/src/api/http.test.ts b/frontend/src/api/http.test.ts index 70ff70d..7e1498a 100644 --- a/frontend/src/api/http.test.ts +++ b/frontend/src/api/http.test.ts @@ -70,4 +70,20 @@ describe('http 401 单飞刷新', () => { await expect(http.get('/x', { silent: true })).rejects.toThrow() expect(vi.mocked(fetch).mock.calls.filter(([u]) => String(u).includes('/auth/refresh'))).toHaveLength(0) }) + + // 回归:登录页死循环。曾经 redirectToLogin 在已处于 /login 时仍赋值 + // location.href='/login' —— 赋同值同样会整页重载,重载后 LicenseProvider + // 再次请求鉴权接口 → 401 → 再重载,用户看到的是登录页一直转圈+闪屏 + // (线上实测 10 分钟 1566 次 401)。这里锁住"在 /login 上不再导航"的行为。 + it('已在 /login 时 401 不再重载页面', async () => { + const loginLocation = { href: 'http://localhost/login', pathname: '/login', search: '' } + Object.defineProperty(window, 'location', { value: loginLocation, writable: true, configurable: true }) + const state = { access: null as string | null, refresh: null as string | null } + const { http } = await freshHttp(state) + vi.mocked(fetch).mockImplementation(async () => jsonResponse({ code: 401, message: 'unauthorized' }, 401)) + + await expect(http.get('/system/license')).rejects.toThrow() + // 关键断言:href 没有被重新赋值(保持原值,不触发重载) + expect(loginLocation.href).toBe('http://localhost/login') + }) })