Why: the change-password modal rendered loose password inputs outside any <form> with no autocomplete or username association (browser password-form warnings; Enter did not submit), and its 401 handling collapsed every cause into "wrong current password". SettingInput masked ALL free-text config values as password fields. Evidence: vitest 24 files / 116 tests incl. new settingInputAttrs matrix; knip and tsc -b && vite build pass; e2e changepw-form spec (driven by the dev-repo e2e.sh plain phase) covers form submit via Enter, autocomplete trio, readonly username and the classified error copy. Impact: ChangePasswordModal uses form onSubmit, htmlFor/id association, username/current-password/new-password autocomplete and reuses humanChangePasswordError; SettingInput renders text inputs unless the field is secret. Refs: 2026-10-12 diagnostic report, increment 3.
26 lines
1.2 KiB
TypeScript
26 lines
1.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { settingInputAttrs } from '../src/components/SettingsModal'
|
|
|
|
// 2026-10-12 增量 3:配置输入按字段类型渲染——此前 SettingInput 默认分支无条件
|
|
// type="password",浏览器把整排设置项当凭据表单(「password 不在 form 中/缺少
|
|
// username」警告的来源之一),且普通文本被无谓遮蔽。新契约:仅秘密字段用密码框。
|
|
describe('settingInputAttrs', () => {
|
|
it('secret=true → 密码框 + new-password', () => {
|
|
expect(settingInputAttrs({ key: 'llm.apiKey', label: '密钥', type: 'string', secret: true } as any))
|
|
.toEqual({ type: 'password', autoComplete: 'new-password' })
|
|
})
|
|
|
|
it('type=secret → 密码框', () => {
|
|
expect(settingInputAttrs({ key: 'x', label: 'X', type: 'secret' } as any).type).toBe('password')
|
|
})
|
|
|
|
it('普通文本 → text + off(不遮蔽、不当凭据)', () => {
|
|
const a = settingInputAttrs({ key: 'llm.baseUrl', label: '地址', type: 'string' } as any)
|
|
expect(a).toEqual({ type: 'text', autoComplete: 'off' })
|
|
})
|
|
|
|
it('无类型标注的默认项 → text', () => {
|
|
expect(settingInputAttrs({ key: 'ui.language', label: '语言' } as any).type).toBe('text')
|
|
})
|
|
})
|