# 年龄输入框修复测试方案 ## 修复概述 针对 `src/pages/patient/components/register.form.tsx` 中年龄输入框的两个问题进行修复: 1. 能调节到负值 2. 能输入任意字符 ## 修复内容 ### 1. NumberWithUnit 组件修改 **文件**: `src/components/NumberWithUnit.tsx` **修改点**: #### 基础属性配置 - 添加 `min={0}` - 防止负值 - 添加 `precision={0}` - 只允许整数 - 添加 `parser={(value) => value?.replace(/\D/g, '') || ''}` - 作为兜底过滤机制 - 添加 `keyboard={true}` - 确保键盘输入正常 #### 实时输入拦截(v1.1 新增) - **onKeyDown 处理器** - 在键盘输入层面拦截非数字字符 - 阻止字母、特殊字符等非数字按键 - 允许功能键(退格、删除、方向键等) - 允许 Ctrl/Cmd 组合键(复制、粘贴、全选等) - 输入法激活时不拦截(避免干扰中文输入) - **onPaste 处理器** - 处理粘贴操作 - 拦截粘贴事件 - 自动过滤粘贴内容中的非数字字符 - 只保留数字部分并更新到输入框 - **onCompositionStart/End 处理器** - 处理输入法输入 - 检测输入法激活状态 - 在输入法确认输入后立即过滤非数字字符 - 完美支持中文输入法等复杂输入场景 **实现效果**: - ✅ 用户按下非数字键时,字符不会出现在输入框中 - ✅ 粘贴包含非数字字符的内容时,自动过滤并只保留数字 - ✅ 使用输入法输入中文后,确认输入时立即过滤 - ✅ parser 作为最后防线,处理可能遗漏的特殊情况 ### 2. 表单验证规则增强 **文件**: `src/validation/patient/registerSchema.ts` **修改点**: 添加自定义验证器: - 检查是否为有效数字 - 检查是否为负数 - 检查是否超过200(合理范围) - 检查是否为整数 ## 测试用例 ### 测试环境准备 1. 启动应用程序 2. 进入患者注册页面 3. 定位到"年龄"输入框 --- ### 分类1:负值输入测试 #### TC-AGE-001: 点击减号按钮测试 **前置条件**: 年龄输入框值为 0 **测试步骤**: 1. 点击年龄输入框的减号按钮多次 **预期结果**: - ✅ 数值保持为 0,不会变成负数 - ✅ 减号按钮应该被禁用或点击无效 **优先级**: P0 (高) --- #### TC-AGE-002: 直接输入负数测试 **测试步骤**: 1. 清空年龄输入框 2. 直接输入 "-5" 3. 点击输入框外部(触发 blur 事件) **预期结果**: - ✅ 输入框自动过滤 "-" 符号,只显示 "5" - ✅ 或者输入框为空(如果只输入了"-") **优先级**: P0 (高) --- #### TC-AGE-003: 通过键盘快捷键输入负数 **测试步骤**: 1. 聚焦到年龄输入框 2. 按下 "负号" 或 "减号" 键 **预期结果**: - ✅ 负号字符不会被输入到输入框中 - ✅ 输入框保持当前值不变 **优先级**: P1 (中) --- ### 分类2:非法字符输入测试 #### TC-AGE-004: 输入字母测试 **测试步骤**: 1. 清空年龄输入框 2. 依次输入: "a", "B", "xyz" 3. 观察输入框内容 **预期结果**: - ✅ 所有字母字符都被过滤,输入框保持为空或显示之前的有效数字 **优先级**: P0 (高) --- #### TC-AGE-005: 输入特殊字符测试 **测试步骤**: 1. 清空年龄输入框 2. 依次尝试输入: "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" 3. 观察输入框内容 **预期结果**: - ✅ 所有特殊字符都被过滤,输入框保持为空或显示之前的有效数字 **优先级**: P0 (高) --- #### TC-AGE-006: 输入中文字符测试 **测试步骤**: 1. 清空年龄输入框 2. 尝试输入中文: "一", "二", "三", "年龄" 3. 观察输入框内容 **预期结果**: - ✅ 所有中文字符都被过滤,输入框保持为空或显示之前的有效数字 **优先级**: P1 (中) --- #### TC-AGE-007: 输入小数点测试 **测试步骤**: 1. 在年龄输入框中输入 "10" 2. 尝试输入小数点 ".",完整输入 "10.5" 3. 点击输入框外部(触发 blur 事件) **预期结果**: - ✅ 小数点及小数部分被自动移除 - ✅ 输入框显示 "10" 或 "105"(取决于 parser 实现) **优先级**: P0 (高) --- #### TC-AGE-008: 混合输入测试 **测试步骤**: 1. 清空年龄输入框 2. 输入混合内容: "12abc34#@!56" 3. 观察输入框内容 **预期结果**: - ✅ 输入框只显示数字部分: "123456" - ✅ 所有非数字字符都被过滤 **优先级**: P1 (中) --- ### 分类3:边界值测试 #### TC-AGE-009: 最小值边界测试 **测试步骤**: 1. 在年龄输入框中输入 "0" 2. 选择单位为 "年" 3. 点击输入框外部(触发验证) **预期结果**: - ✅ 输入框接受 0 作为有效值 - ✅ 不显示任何验证错误 **优先级**: P0 (高) --- #### TC-AGE-010: 最大值边界测试 **测试步骤**: 1. 在年龄输入框中输入 "200" 2. 选择单位为 "年" 3. 点击输入框外部(触发验证) **预期结果**: - ✅ 输入框接受 200 作为有效值 - ✅ 不显示任何验证错误 **优先级**: P0 (高) --- #### TC-AGE-011: 超过最大值测试 **测试步骤**: 1. 在年龄输入框中输入 "201" 2. 选择单位为 "年" 3. 点击输入框外部(触发验证) **预期结果**: - ✅ 显示验证错误: "年龄超出合理范围(最大200)" - ✅ 表单提交被阻止 **优先级**: P0 (高) --- #### TC-AGE-012: 极大值测试 **测试步骤**: 1. 在年龄输入框中输入 "999999" 2. 选择单位为 "年" 3. 点击输入框外部(触发验证) **预期结果**: - ✅ 显示验证错误: "年龄超出合理范围(最大200)" - ✅ 表单提交被阻止 **优先级**: P1 (中) --- ### 分类4:不同单位测试 #### TC-AGE-013: 年单位有效值测试 **测试步骤**: 1. 在年龄输入框中输入 "25" 2. 选择单位为 "年" 3. 点击输入框外部 **预期结果**: - ✅ 输入框显示 "25" - ✅ 单位显示 "年" - ✅ 不显示任何验证错误 **优先级**: P0 (高) --- #### TC-AGE-014: 月单位有效值测试 **测试步骤**: 1. 在年龄输入框中输入 "18" 2. 选择单位为 "月" 3. 点击输入框外部 **预期结果**: - ✅ 输入框显示 "18" - ✅ 单位显示 "月" - ✅ 不显示任何验证错误 **优先级**: P0 (高) --- #### TC-AGE-015: 天单位有效值测试 **测试步骤**: 1. 在年龄输入框中输入 "30" 2. 选择单位为 "天" 3. 点击输入框外部 **预期结果**: - ✅ 输入框显示 "30" - ✅ 单位显示 "天" - ✅ 不显示任何验证错误 **优先级**: P0 (高) --- #### TC-AGE-016: 切换单位后保持值测试 **测试步骤**: 1. 在年龄输入框中输入 "25" 2. 选择单位为 "年" 3. 切换单位为 "月" 4. 观察输入框的值 **预期结果**: - ✅ 数字值保持为 "25" - ✅ 单位更新为 "月" - ✅ 出生日期相应更新 **优先级**: P1 (中) --- ### 分类5:复制粘贴测试 #### TC-AGE-017: 粘贴有效数字测试 **测试步骤**: 1. 复制数字 "30" 2. 在年龄输入框中粘贴(Ctrl+V 或 Cmd+V) 3. 观察输入框内容 **预期结果**: - ✅ 输入框显示 "30" - ✅ 不显示任何验证错误 **优先级**: P1 (中) --- #### TC-AGE-018: 粘贴负数测试 **测试步骤**: 1. 复制文本 "-15" 2. 在年龄输入框中粘贴 3. 观察输入框内容 **预期结果**: - ✅ 负号被过滤,输入框显示 "15" - ✅ 或者粘贴操作被阻止 **优先级**: P0 (高) --- #### TC-AGE-019: 粘贴混合内容测试 **测试步骤**: 1. 复制文本 "abc123xyz456" 2. 在年龄输入框中粘贴 3. 观察输入框内容 **预期结果**: - ✅ 只有数字被保留,输入框显示 "123456" - ✅ 字母字符被自动过滤 **优先级**: P1 (中) --- ### 分类6:键盘输入测试 #### TC-AGE-020: 使用方向键调整数值 **测试步骤**: 1. 在年龄输入框中输入 "10" 2. 聚焦到输入框 3. 按下向上箭头键(↑)多次 4. 按下向下箭头键(↓)多次 **预期结果**: - ✅ 向上箭头增加数值 - ✅ 向下箭头减少数值 - ✅ 数值不会低于 0 **优先级**: P1 (中) --- #### TC-AGE-021: Enter 键行为测试 **测试步骤**: 1. 在年龄输入框中输入 "25" 2. 按下 Enter 键 **预期结果**: - ✅ 值被保存 - ✅ 触发表单验证(如果需要) - ✅ 不提交整个表单 **优先级**: P2 (低) --- ### 分类7:年龄与出生日期联动测试 #### TC-AGE-022: 修改年龄更新出生日期 **测试步骤**: 1. 在年龄输入框中输入 "25" 2. 选择单位为 "年" 3. 观察出生日期字段 **预期结果**: - ✅ 出生日期自动计算并更新 - ✅ 出生日期应该是当前日期减去 25 年 **优先级**: P0 (高) --- #### TC-AGE-023: 输入负数不影响出生日期 **测试步骤**: 1. 记录当前出生日期值 2. 尝试在年龄输入框输入 "-10" 3. 观察出生日期是否变化 **预期结果**: - ✅ 负数被过滤 - ✅ 出生日期保持不变或根据有效部分更新 **优先级**: P1 (中) --- ### 分类8:表单验证集成测试 #### TC-AGE-024: 提交空年龄表单 **测试步骤**: 1. 清空年龄输入框 2. 尝试提交表单 **预期结果**: - ✅ 显示验证错误: "请输入有效的年龄" - ✅ 表单提交被阻止 **优先级**: P0 (高) --- #### TC-AGE-025: 提交无效年龄表单 **测试步骤**: 1. 在年龄输入框输入 "300" 2. 尝试提交表单 **预期结果**: - ✅ 显示验证错误: "年龄超出合理范围(最大200)" - ✅ 表单提交被阻止 **优先级**: P0 (高) --- #### TC-AGE-026: 提交有效年龄表单 **测试步骤**: 1. 填写所有必填字段 2. 在年龄输入框输入 "30",单位选择 "年" 3. 提交表单 **预期结果**: - ✅ 表单验证通过 - ✅ 表单成功提交 - ✅ 年龄数据正确保存 **优先级**: P0 (高) --- ### 分类9:浏览器兼容性测试 #### TC-AGE-027: Chrome 浏览器测试 **测试步骤**: 在 Chrome 浏览器中执行 TC-AGE-001 到 TC-AGE-026 **预期结果**: 所有测试用例通过 **优先级**: P0 (高) --- #### TC-AGE-028: Firefox 浏览器测试 **测试步骤**: 在 Firefox 浏览器中执行核心测试用例(TC-AGE-001, 004, 007, 018) **预期结果**: 所有测试用例通过 **优先级**: P1 (中) --- #### TC-AGE-029: Edge 浏览器测试 **测试步骤**: 在 Edge 浏览器中执行核心测试用例 **预期结果**: 所有测试用例通过 **优先级**: P1 (中) --- ### 分类10:实时输入拦截测试(v1.1 新增) #### TC-AGE-032: 实时拦截字母输入测试 **测试步骤**: 1. 聚焦到年龄输入框 2. 尝试按键盘输入字母 "a" 3. 观察输入框变化 **预期结果**: - ✅ 字母 "a" **不会出现**在输入框中(实时拦截) - ✅ 输入框内容保持不变 - ✅ 没有任何闪烁或字符出现后消失的情况 **优先级**: P0 (高) --- #### TC-AGE-033: 实时拦截特殊字符输入测试 **测试步骤**: 1. 聚焦到年龄输入框 2. 尝试按键盘输入特殊字符 "@"、"#"、"!" 3. 观察输入框变化 **预期结果**: - ✅ 特殊字符**不会出现**在输入框中(实时拦截) - ✅ 输入框内容保持不变 **优先级**: P0 (高) --- #### TC-AGE-034: 实时拦截减号输入测试 **测试步骤**: 1. 聚焦到年龄输入框 2. 按键盘输入减号 "-" 3. 观察输入框变化 **预期结果**: - ✅ 减号**不会出现**在输入框中(实时拦截) - ✅ 输入框内容保持不变 **优先级**: P0 (高) --- #### TC-AGE-035: 中文输入法实时过滤测试 **测试步骤**: 1. 聚焦到年龄输入框 2. 切换到中文输入法 3. 输入拼音 "nian"(年) 4. 按空格或回车确认输入 5. 观察输入框内容 **预期结果**: - ✅ 在输入拼音过程中,拼音可以正常显示(不干扰输入法) - ✅ 确认输入后,中文字符立即被过滤 - ✅ 输入框最终为空或保持之前的有效数字 **优先级**: P0 (高) --- #### TC-AGE-036: 粘贴实时过滤测试 **测试步骤**: 1. 复制文本 "age25years" 2. 在年龄输入框中粘贴 3. 观察输入框变化过程 **预期结果**: - ✅ 粘贴后,输入框**立即显示** "25"(实时过滤) - ✅ 不会先显示 "age25years" 然后再过滤 - ✅ 用户感知到的是直接粘贴了 "25" **优先级**: P0 (高) --- #### TC-AGE-037: 混合输入实时拦截测试 **测试步骤**: 1. 清空年龄输入框 2. 依次按键输入: "1", "a", "2", "b", "3" 3. 观察每次按键后的输入框内容 **预期结果**: - ✅ 输入 "1" 后显示 "1" - ✅ 输入 "a" 后仍显示 "1"(字母被拦截) - ✅ 输入 "2" 后显示 "12" - ✅ 输入 "b" 后仍显示 "12"(字母被拦截) - ✅ 输入 "3" 后显示 "123" - ✅ **全程没有字母出现在输入框中** **优先级**: P0 (高) --- #### TC-AGE-038: Ctrl+V 粘贴功能测试 **测试步骤**: 1. 复制数字 "50" 2. 聚焦到年龄输入框 3. 按 Ctrl+V(或 Cmd+V)粘贴 **预期结果**: - ✅ Ctrl/Cmd 组合键不被拦截 - ✅ 粘贴功能正常工作 - ✅ 输入框显示 "50" **优先级**: P0 (高) --- #### TC-AGE-039: 功能键正常工作测试 **测试步骤**: 1. 在年龄输入框输入 "123" 2. 按 Home 键(光标移到开头) 3. 按 End 键(光标移到结尾) 4. 按 Backspace 键 5. 按 Delete 键 **预期结果**: - ✅ Home、End、Backspace、Delete 等功能键正常工作 - ✅ 不被拦截处理器影响 **优先级**: P1 (中) --- #### TC-AGE-040: 输入法切换时的稳定性测试 **测试步骤**: 1. 聚焦到年龄输入框 2. 在中英文输入法之间来回切换 3. 尝试在不同输入法状态下输入 4. 观察输入框行为 **预期结果**: - ✅ 输入法切换不影响输入拦截功能 - ✅ 无论哪种输入法,非数字字符都被正确处理 - ✅ 无异常报错或卡顿 **优先级**: P1 (中) --- ### 分类11:性能与用户体验测试 #### TC-AGE-030: 快速连续输入测试 **测试步骤**: 1. 快速连续输入数字: "1234567890" 2. 观察输入框响应 **预期结果**: - ✅ 输入响应流畅,无延迟 - ✅ 所有数字都被正确显示 - ✅ 超过最大值时显示验证错误 **优先级**: P1 (中) --- #### TC-AGE-031: 错误提示清晰度测试 **测试步骤**: 1. 在年龄输入框输入 "300" 2. 点击输入框外部 3. 观察错误提示 **预期结果**: - ✅ 错误提示清晰可见 - ✅ 错误信息准确描述问题 - ✅ 错误提示位置合理 **优先级**: P2 (低) --- ## 测试执行记录表 | 用例编号 | 测试日期 | 测试人员 | 测试结果 | 备注 | |---------|---------|---------|---------|------| | TC-AGE-001 | | | ⬜ Pass / ❌ Fail | 负值输入 | | TC-AGE-002 | | | ⬜ Pass / ❌ Fail | 负值输入 | | TC-AGE-003 | | | ⬜ Pass / ❌ Fail | 负值输入 | | TC-AGE-004 | | | ⬜ Pass / ❌ Fail | 非法字符 | | TC-AGE-005 | | | ⬜ Pass / ❌ Fail | 非法字符 | | TC-AGE-006 | | | ⬜ Pass / ❌ Fail | 非法字符 | | TC-AGE-007 | | | ⬜ Pass / ❌ Fail | 非法字符 | | TC-AGE-008 | | | ⬜ Pass / ❌ Fail | 非法字符 | | TC-AGE-009 | | | ⬜ Pass / ❌ Fail | 边界值 | | TC-AGE-010 | | | ⬜ Pass / ❌ Fail | 边界值 | | TC-AGE-011 | | | ⬜ Pass / ❌ Fail | 边界值 | | TC-AGE-012 | | | ⬜ Pass / ❌ Fail | 边界值 | | TC-AGE-013 | | | ⬜ Pass / ❌ Fail | 单位测试 | | TC-AGE-014 | | | ⬜ Pass / ❌ Fail | 单位测试 | | TC-AGE-015 | | | ⬜ Pass / ❌ Fail | 单位测试 | | TC-AGE-016 | | | ⬜ Pass / ❌ Fail | 单位测试 | | TC-AGE-017 | | | ⬜ Pass / ❌ Fail | 粘贴测试 | | TC-AGE-018 | | | ⬜ Pass / ❌ Fail | 粘贴测试 | | TC-AGE-019 | | | ⬜ Pass / ❌ Fail | 粘贴测试 | | TC-AGE-020 | | | ⬜ Pass / ❌ Fail | 键盘输入 | | TC-AGE-021 | | | ⬜ Pass / ❌ Fail | 键盘输入 | | TC-AGE-022 | | | ⬜ Pass / ❌ Fail | 联动测试 | | TC-AGE-023 | | | ⬜ Pass / ❌ Fail | 联动测试 | | TC-AGE-024 | | | ⬜ Pass / ❌ Fail | 表单验证 | | TC-AGE-025 | | | ⬜ Pass / ❌ Fail | 表单验证 | | TC-AGE-026 | | | ⬜ Pass / ❌ Fail | 表单验证 | | TC-AGE-027 | | | ⬜ Pass / ❌ Fail | 浏览器兼容 | | TC-AGE-028 | | | ⬜ Pass / ❌ Fail | 浏览器兼容 | | TC-AGE-029 | | | ⬜ Pass / ❌ Fail | 浏览器兼容 | | TC-AGE-030 | | | ⬜ Pass / ❌ Fail | 性能测试 | | TC-AGE-031 | | | ⬜ Pass / ❌ Fail | 用户体验 | | **TC-AGE-032** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-033** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-034** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-035** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-036** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-037** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-038** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-039** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | | **TC-AGE-040** | | | ⬜ Pass / ❌ Fail | **实时拦截 (v1.1)** | ## 测试优先级说明 - **P0 (高)**: 核心功能,必须通过 - **P1 (中)**: 重要功能,建议通过 - **P2 (低)**: 辅助功能,可选通过 ## 缺陷记录模板 如果测试中发现问题,请记录: ``` 缺陷ID: BUG-AGE-XXX 相关用例: TC-AGE-XXX 严重程度: Critical / Major / Minor 复现步骤: 1. ... 2. ... 3. ... 实际结果: ... 预期结果: ... 附件: (截图/视频) ``` ## 测试完成标准 - ✅ 所有 P0 优先级测试用例通过 - ✅ 至少 80% 的 P1 优先级测试用例通过 - ✅ 所有发现的 Critical/Major 缺陷已修复 - ✅ 回归测试通过 --- ## 版本历史 | 版本 | 日期 | 修改内容 | 修改人 | |------|------|---------|--------| | v1.0 | 2025-11-28 | 初始版本,包含基础输入限制和表单验证 | - | | v1.1 | 2025-11-28 | 新增实时输入拦截功能(9个新测试用例:TC-AGE-032~040) | - | --- **测试计划创建日期**: 2025-11-28 **最后更新日期**: 2025-11-28 **文档版本**: v1.1