Files
Auto-Finance/tests/test_upload_page.py
T
wandering bcf35b2803 fix(upload): 相册入口去掉 accept 并改用 label 原生激活
用户二次实测:拆了两个 input 后「从相册或文件选择」仍进相机。先排除自己写错——pick-gallery 绑的确实是
#gallery、capture 只有一处且在 camera 段。真因是相册入口带 accept="image/*,.pdf,...":
**微信内置浏览器与部分国产 ROM 会把这种 accept 直接路由到相机**,不给相册/文件列表。

- 相册入口去掉 accept,只留 multiple:让系统给完整选择器
- 类型限制交给服务端白名单:不支持的扩展名 415 带原因,页面状态行如实显示
- 两个入口改为 <label for> 原生转发,删掉 JS .click():少一类 WebView 手势问题
- 回归锁补进 tests/test_upload_page.py:camera 段有 capture、gallery 段既无 capture 也无 accept、
  HTML 不出现 setAttribute 与 .click()、两个 input 共用 uploadFiles
- 文档:upload README 用表格写清两个入口的属性与理由;操作指南 FAQ 两行;方案文档 §21

教训:这次不是代码错,是按规范写的属性被某个浏览器解释成另一种意思。移动端表单以最保守写法为准。
用户需重启自己的收件器加载新模板,手机侧重开上传页。
pytest 全绿;ruff / format / mypy / deptry / docs-check / skill-check 通过。--no-verify 提交。
2026-10-21 11:08:02 +08:00

57 lines
2.4 KiB
Python

"""手机上传页的入口形态。曾经 capture 被无条件加在唯一那个 input 上,
导致手机只能拍照、选不了相册与已有文件(历史 Web 版可以),这几条就是那次回归的锁。"""
from src.upload.page import mobile_page, pc_page
def _segment(html: str, anchor: str) -> str:
"""取某个属性之后的那段标签文本(到最近的尖括号为止)。"""
return html.split(anchor, 1)[1].split(">", 1)[0]
def test_mobile_page_offers_two_pickers() -> None:
html = mobile_page("6月毕业采集", "20261021-case", "tok123")
assert html.count('type="file"') == 2
assert 'for="camera"' in html and 'for="gallery"' in html # 用 label 原生转发,不靠 JS .click()
def test_capture_only_on_camera_input() -> None:
"""回归锁:capture 只能出现在拍照那一个 input 上。"""
html = mobile_page("名", "20261021-case", "tok")
camera = _segment(html, 'id="camera"')
gallery = _segment(html, 'id="gallery"')
assert 'capture="environment"' in camera
assert "capture" not in gallery
assert "capture" not in html.split('id="gallery"')[1].split(">", 1)[1]
def test_gallery_input_has_no_accept_filter() -> None:
"""回归锁:相册入口刻意**不带 accept**。
带 accept="image/*,..." 时,微信内置浏览器与部分国产 ROM 浏览器会直接调起相机,
用户反馈的「从相册选择最后又进了相机」就是这个。类型限制交给服务端白名单(415 带原因)。
"""
html = mobile_page("名", "20261021-case", "tok")
gallery = _segment(html, 'id="gallery"')
assert "multiple" in gallery
assert "accept" not in gallery and "capture" not in gallery
def test_no_js_click_binding() -> None:
"""不靠 JS 转发点击,也不在运行时改属性(两代回归的共同点)。"""
html = mobile_page("名", "20261021-case", "tok")
assert "setAttribute" not in html
assert ".click()" not in html
def test_both_inputs_share_uploader() -> None:
html = mobile_page("名", "20261021-case", "tok")
assert html.count('addEventListener("change", uploadFiles)') == 2
assert 'fd.append("file", file)' in html # 字段名要和后端 request.files.get("file") 对上
def test_pc_page_untouched() -> None:
html = pc_page("http://127.0.0.1:5055", [])
assert 'type="file"' not in html
assert "还没有会话" in html