From dda5ad1e5a1cfc2d399ec99cb3ff5a3ac2820396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=81=E5=86=9C=E9=98=BF=E6=A5=A0?= Date: Tue, 8 Sep 2026 21:42:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E7=99=BB=E5=BD=95=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A1=A5=E5=85=85=E9=9A=90=E8=97=8F=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=90=8D=E5=AD=97=E6=AE=B5=E4=BB=A5=E5=85=BC=E5=AE=B9=20Safari?= =?UTF-8?q?=20=E5=AF=86=E7=A0=81=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Safari/WebKit 在明文 HTTP 下不保存 Secure Cookie(无 localhost 豁免, Chrome/Firefox 有),__Host- 会话被静默丢弃导致登录成功后仍弹回登录页; 本机调试需以 --dev 启动(pn_session 无 Secure,loopback-only 守卫,§7.3-3)。 纯密码表单另令 Safari 保存密码弹窗要求手动输入用户名:补充 sr-only 用户名 输入(autoComplete=username,只读预填 admin),弹窗不再阻断登录。 新增 login.test.tsx 回归测试锁定用户名/密码字段的自动填充标记。 --- web/src/pages/Login.tsx | 12 ++++++++++++ web/tests/login.test.tsx | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 web/tests/login.test.tsx diff --git a/web/src/pages/Login.tsx b/web/src/pages/Login.tsx index 5112982..ef15b8f 100644 --- a/web/src/pages/Login.tsx +++ b/web/src/pages/Login.tsx @@ -49,6 +49,18 @@ export default function Login() {

管理员登录

请输入管理密码以继续

+ + +
diff --git a/web/tests/login.test.tsx b/web/tests/login.test.tsx new file mode 100644 index 0000000..a243851 --- /dev/null +++ b/web/tests/login.test.tsx @@ -0,0 +1,30 @@ +import { describe, expect, it, vi } from 'vitest' +import { render, screen } from '@testing-library/react' +import { MemoryRouter } from 'react-router' +import Login from '../src/pages/Login' + +vi.mock('../src/lib/auth', () => ({ + useAuth: () => ({ login: vi.fn(), authenticated: false }), +})) +vi.mock('../src/features/site', () => ({ + useDocumentTitle: () => {}, +})) + +describe('Login 表单密码管理器适配', () => { + it('暴露隐藏用户名字段与 current-password 自动填充标记', () => { + render( + + + , + ) + + const username = screen.getByLabelText('用户名') as HTMLInputElement + expect(username.type).toBe('text') + expect(username.value).toBe('admin') + expect(username.readOnly).toBe(true) + expect(username.getAttribute('autocomplete')).toBe('username') + + const password = screen.getByLabelText('管理密码') as HTMLInputElement + expect(password.getAttribute('autocomplete')).toBe('current-password') + }) +})