编辑与阅读 30 分钟模拟器测试
测试范围与环境
- 日期:2026-10-23,报告时间使用 Asia/Shanghai。
- 录屏开始:09:34:17;录屏结束:10:04:18,墙钟时长 1,801.04 秒(30 分 1 秒)。
- 设备:
emulator-5556,Android 15,x86_64,320 × 640,160 dpi。 - 安装版本:
com.mynote.mynote_mobile,versionName=0.1.0,versionCode=1,Debug。 - 设备返回的安装更新时间:2026-10-22 13:55:09,设备时区 GMT。
- 本次未重新构建或安装 APK,不能将已安装版本等同于当前源码。
- 当前源码检查基准:
9b3824b604b35da88b301e8f9de16a161327aa34。 - 独立本地测试仓库:
QA_EditRead_20261023;不执行远端同步,不编辑原有仓库的笔记。 - 使用 ADB 进行有目标的操作,以截图、无障碍树、磁盘正文和 Flutter 调试事件交叉验证。
- 夹具通过测试仓库直接写入;输入、保存、撤销、切换和恢复操作通过应用界面执行。
- 临时测试工具和原始证据保存在
build/edit-read-30min/,不加入 Git。
结论
完成 30 分钟有目标的模拟器测试及全程分段录屏。 以下保留修复前的测试结论;问题一的后续修复及验证见对应小节。
- 常规输入、保存重开、撤销重做、剪切恢复、Unicode、草稿恢复、Markdown、图片、大纲定位与横屏模式切换检查通过。
- 八轮反复编辑产生的 40 次一致性检查全部通过,重启后的已保存内容仍一致。
- 确认新建笔记红屏,4/4 次复现,第四次捕获了控制器释放后仍被使用的首发错误。
- 大文件快速自动输入未完整进入正文;慢速输入可完整保存,尚未隔离注入通道和应用性能的影响。
- 无障碍语义树断言共 17 条,在最后反复阅读滚动中再次出现,并伴随无障碍树间歇缺失;不能将阅读稳定性整体判为通过。
- 录屏原始分段保留;合并播放版。
测试数据
| 文件 | 用途 |
|---|---|
01-edit.md |
新建、空白编辑器、代码复制粘贴、中文和 emoji 保存 |
02-second.md |
多行输入、保存重开、撤销重做、草稿恢复、关闭确认 |
03-markdown.md |
六级标题、强调、嵌套列表、引用、表格、代码、库内链接、缩放 |
04-long.md |
48,812 字符、180 节的长文,滚动、大纲跳转、双击定位源码 |
05-leading-blank.md |
三个开头空行、中文和 emoji,反复编辑与跨标签历史验证 |
06-unclosed.md |
未闭合且语言未知的代码围栏 |
07-large.md |
572,035 字符,超过 524,288 UTF-16 单元的高亮阈值 |
08-no-keyboard.md |
创建前收起键盘,再次验证新建红屏 |
09-images.md |
相对路径图片、缺失图片降级、横屏阅读与模式切换 |
10-blank-restore.md |
保留开头空行的未保存 Unicode 草稿重启恢复 |
11-vm-repro.md |
第四次新建,采集完整 Flutter 错误事件 |
逐项结果
E01–E04 已整理为可重复执行的模拟器脚本,包含运行方式、断言及证据输出说明。
| 编号 | 操作与核验方法 | 结果 |
|---|---|---|
| E01 | 独立新库创建首篇笔记;重启后再建;收起键盘后再建;启用 VM 事件后再建 | 失败,4/4 红屏,详见问题一 |
| E02 | 实际键入两行正文,核对编辑器文本与换行 | 通过 |
| E03 | 点击保存,读取测试笔记磁盘正文逐字比较 | 通过 |
| E04 | 关闭已保存笔记,从文件选择器重开,再查看源码 | 通过,与磁盘一致 |
| E05–E06 | 插入 APPEND,通过菜单撤销和重做 |
通过,精确恢复前后正文 |
| E07 | 未保存时强制停止应用,再启动 | 通过,草稿恢复,磁盘仍保留保存前版本 |
| E08 | 关闭未保存笔记,选择取消 | 通过,标签和草稿保留 |
| E09 | 再次关闭,选择丢弃并关闭 | 通过,磁盘已保存版本不变 |
| E10 | 预览复制含中文、emoji 的多行代码,在空白编辑器长按粘贴 | 通过 |
| E11 | 保存粘贴内容,将磁盘全文与编辑器比较 | 通过,Unicode、换行和代码完整 |
| E12–E13 | 长按、全选、剪切,再撤销 | 通过,清空编辑器后可完整恢复中文、emoji 和换行,已保存文件不受影响 |
| R01 | 逐屏查看 Markdown 标题、列表、引用、表格、代码及中文、emoji | 通过,可见内容布局与样式正常 |
| R01a | 点击库内链接,再通过后退返回 | 通过,打开目标笔记并返回原预览位置 |
| R02 | 长文大纲筛选 180,点击第 180 节 |
通过,末节和 END-LONG-180 可见 |
| R03–R04 | 在末节正文双击,进入源码,插入定位标记 | 通过,插入位置 48,546,位于原文末尾约 99.5% 处 |
| R05 | 撤销长文定位标记,将源码全文与磁盘比较 | 通过,原文恢复 |
| R06 | 预览及编辑未闭合、未知语言代码围栏 | 通过,正文无改写,无红屏 |
| Z01 | 连续放大、缩小预览,观察字号边界与代码块高度 | 字号边界正常;语义树断言在此阶段首次捕获,详见问题三 |
| Z02 | 预览反复缩放后转源码,逐字核对 | 通过,正文不变 |
| Z03 | 编辑器内双指缩放,核对模式与源码 | 通过,仍在编辑模式,正文不变 |
| Z04 | 重启后再次连续放大/缩小,共六次双指手势 | 六次均未新增 Flutter 错误;不能消除前一次语义树断言的事实 |
| L01 | 打开并切换到 572,035 字符大文件编辑器 | 能显示;无障碍树未返回正文编辑框,不能用树核验全文 |
| L02 | 快速键入 LARGE-EDIT-TEST 并保存 |
不通过预期全文断言;实际仅增加 LARGE,详见问题二 |
| L03 | 再输入 XY,等待后保存 |
通过,磁盘恰好增加两个字符,原文其余内容保持完整 |
| C00 | 打开包含三个开头空行的夹具并进入编辑 | 通过,空行保留 |
| C01–C08 | 连续八轮输入、保存、预览、切换到另一标签再返回、撤销、重做 | 40 次逐字一致性检查全部通过;历史保留,标签内容不串写 |
| C09 | 八轮后强制停止并重新启动 | 通过,已保存全文保持一致 |
| D01–D04 | 在开头空行之后编辑 Unicode 笔记,未保存重启,再保存 | 通过,三行开头空行、中文、emoji 和新增正文完整恢复,保存前磁盘不变 |
| I01 | 阅读 640 × 320 的相对路径图片及不存在的图片 | 通过,四象限内容、2:1 比例正常;缺失图片显示替代文字,正文继续显示 |
| O01 | 竖屏进入横屏,切换编辑/预览,再回到竖屏 | 通过,源码逐字一致,未见布局溢出;键盘会压缩横屏可编辑高度 |
| R07 | 最后连续 16 次阅读滚动,截图与无障碍树交叉核对 | 画面保持预览,但 7 次树采集缺失,日志再次出现语义树断言,整体不通过 |
已发现问题
问题一:创建笔记后 Flutter 红屏
- 严重程度:高,阻断继续编辑,需要重启应用恢复。
- 复现:4/4。
- 步骤:
- 在独立本地仓库点击新建笔记。
- 输入合法 Markdown 文件名并点击创建。
- 界面出现红色错误页。
- 原始错误:
framework.dart:6281,_dependents.isEmpty断言失败。 - 第四次在 10:02:40 捕获到更早的错误:
A TextEditingController was used after being disposed.。- 随后依次出现同类 widgets 错误、
_dependents.isEmpty、Tried to build dirty widget in the wrong build scope.。 - 应优先排查新建路径对话框中控制器的释放时机;本次未修改代码验证修复。
- 随后依次出现同类 widgets 错误、
- 第三次创建前已经收起键盘,仍复现;不能简单归因于键盘未关闭。
- 笔记文件实际已创建;强制停止并重新启动后,可以打开笔记并编辑。
- 首次截图。
- 第二次截图。
- 第三次截图。
- 第四次截图。
- 完整 Flutter 异常事件。
后续修复
- 路径输入改用组件自身管理的控制器,控制器会随对话框组件卸载释放,覆盖关闭动画期间的使用。
- 新建和移动/重命名共用这项修复;保留默认路径、键盘提交、取消、外部关闭及原有文件检查。
- 新增六种对话框关闭路径的组件回归测试;修复前“点击创建”复现同类异常,修复后六项通过。
- 修复后完整
flutter test:351 项全部通过;flutter analyze仍只有原先的 1 条格式 info,无新增问题。 - Android x86_64 Debug APK 已成功构建、覆盖安装并重启模拟器应用。
- 首次构建遇到 Windows Dart 编译器崩溃,完整测试结束后单独重试构建成功。
- 模拟器回测:连续三次新建(包括键盘提交)后均可立即编辑和保存,取消与移动/重命名正常,正文逐字一致。
- 本次回测 Flutter VM 事件中未捕获到
Flutter.Error;问题一在上述回归场景中已修复。 - 修复回测录屏。
- 重命名后编辑器截图。
- 问题二、三不在本次修复范围内,保留待处理。
问题二:大文件快速输入未完整进入正文
- 严重程度:中,影响大文件编辑可靠性;Debug 模拟器下复现。
- 文件:572,035 字符,572,035 UTF-16 单元。
- 自动快速输入 16 个字符
LARGE-EDIT-TEST,随后观察并保存。 - 编辑器截图只显示前缀
LARG,稍后为LARGE;磁盘实际只增加LARGE五个字符。 - 原有正文其余部分完整,没有证据表明保存操作丢掉已在编辑器中的字符。
- 后续输入
XY并等待后保存,两个字符完整进入磁盘。 - 期间出现多条跳帧日志,操作响应明显迟缓。
- 当前证据无法区分输入注入节奏、输入法和应用主线程处理各自的影响;不将其表述为已确认的保存丢字问题。
- 快速输入截图。
- 保存后截图。
问题三:阅读滚动期间反复出现语义树更新断言
- 严重程度:中,影响无障碍语义树可靠性;界面仍可操作,未发生进程退出。
- 09:50:07 的 Flutter 调试事件报告 scheduler callback 异常。
- 共捕获 17 条语义树异常事件:
semantics.dart:3275,owner!._nodes.containsKey(id):4 条。semantics.dart:3013,!child.attached:13 条。
- 堆栈包括
SemanticsNode.detach和RenderEditable.assembleSemanticsNode。 - 事件发生在大文件切换回 Markdown 后、预览继续放大的时间附近;不能据此确定唯一触发条件。
- 无障碍树采集处于开启状态;重启后进行六次放大/缩小时没有新增同类异常。
- 10:03:11–10:04:12 的最终反复阅读滚动再次出现 16 条,说明并非只在缩放时发生。
- 最后 16 次滚动中,有 7 次无障碍树没有返回工具栏和正文语义节点。
- 逐张复核这些截图,画面均仍为正常预览;自动“预览模式存在”断言失败是空语义树造成的,不是切换到了编辑模式。
- 这些空树样本与语义树异常处于同一测试阶段,不能只归类为脚本坐标定位错误。
- 七张截图复核。
- 尚未验证真实读屏服务的行为,也未确认与自动采集无关时的触发频率。
- 完整调试事件保存在
build/edit-read-30min/flutter-vm-events.jsonl。
源码检查
flutter test:345 项全部通过。flutter analyze:未通过零问题标准,有 1 条已有 info:test/mp3_refresh_view_test.dart:37:11。curly_braces_in_flow_control_structures。
- 上述检查针对当前源码;模拟器测试针对原先安装的 APK,两者不是同一层面的验证。
- 本次仅记录结果,不修改业务代码,不修复已有格式提示。
证据与限制
- 录屏:
build/edit-read-30min/part-*.mp4,共 10 段,Android 单次录屏最长约三分钟,因此分段采集。 - 测试墙钟时长 30 分 1 秒;源录屏时间戳合并后为约 30 分 11 秒,操作复现时间以
actions.jsonl为准。 - 合并播放版规范为 15 fps;原始分段和直接合并版均保留。
- 操作时间线与检查记录:
build/edit-read-30min/actions.jsonl。 - 系统日志:
build/edit-read-30min/logcat.txt。 - Flutter 调试事件:
build/edit-read-30min/flutter-vm-events.jsonl;后半程启用,不能覆盖前期全部异常。 - 本次重点为编辑与阅读;不验证远端同步、语音录制播放、真机输入法及 Release 性能。
- 自动输入、无障碍采集和录屏本身会影响模拟器负载,性能观察不能等同于真机基准。
- 自动脚本因临时提示覆盖点击坐标、保留文件过滤条件和界面重排发生过中断;重新观测并调整测试动作后通过,不将这些脚本定位失败计为产品缺陷。
- 录屏使用 Android
screenrecord,不包含音频;横屏阶段另有原始分辨率截图用于布局核验。
