A8 今日头条 (Toutiao) — 真机 E2E 测试计划
Status: v0.3 计划 (2026-05-24 update) — v0.2 stub A8ToutiaoE2ETest.kt 已落;v0.3 新增 ToutiaoSignBridge (hidden WebView 跑 acrawler.js 取 _signature) + ApiClient 3 endpoint 接通 + collector fan-out。Win dev box 跑 JVM 单测 (WebSignBridgeHelpersTest + ToutiaoApiClientV03Test + ToutiaoLocalCollectorV03Test) ✅;真机 E2E 仍需 Mac/Linux + 真机 + 真账号。
范围
v0.3 surface (本轮新增 — 三家 v0.3 模板):
- ✅ profile (
/passport/account/info/v2/?aid=24, unsigned passport endpoint, v0.2 已通) - 🆕 feed → KIND_READ (
/api/news/feed/v90/?category=__all__, 需_signature) - 🆕 collection → KIND_COLLECTION (
/article/v2/tab_comments/, 需_signature) - 🆕 search history → KIND_SEARCH (
/api/search/content/?keyword=, 需_signature)
_signature 由 ToutiaoSignBridge 在登录 cookie 注入后的 hidden WebView 里跑 window.byted_acrawler.sign({url, aid:24, platform:'PC'}) 拿 — 不复刻 acrawler.js(每 4-8 周 rotate 函数名),直接复用平台自带签名 JS。Bridge probe 3 个候选函数名: byted_acrawler.sign / _0x32d839 / acrawler.sign。
Graceful degrade:
- bridge warmUp 失败 (WebView 加载超时 / SDK 没出现) → 跳过 3 个 v0.3 端点, v0.2 profile 仍 emit
- 3 个 endpoint 任一 signUrl 返 null (函数名 rotate) → 短路 (不发 HTTP), ApiClient
lastErrorCode=-99 - 任一 endpoint 返 412 / status_code != 0 → 其它两个继续
v03Attempted 字段在 SnapshotResult.Ok 透出 → UI banner 区分三种状态: "v0.3 完整命中 (N 推荐/M 收藏/K 搜索)" / "v0.3 attempted 但 0 抓到" / "v0.2 fallback (signProvider 未注入)"。
WebView 登录 → SocialCookieWebViewScreen 提取 cookie
↓ (passport_uid / multi_sids / sessionid / ttwid / __ac_nonce)
HubLocalViewModel.syncToutiao()
↓
ToutiaoLocalCollector.snapshot()
↓ ToutiaoApiClient.fetchProfile (1 endpoint, 无 _signature)
↓ JSON 拼装写 filesDir/.chainlesschain/staging/social-toutiao.json (1 profile event)
↓
LocalCcRunner.syncAdapter("social-toutiao", path)
↓ adapter._syncViaSnapshot → person-self with toutiao-uid identifier
↓
UI 显示 "已同步账号 profile (v0.2)。历史/收藏/搜索需 v0.3 _signature 接通"前置(一次性)
- 真头条账号 (v0.2 不需要有内容,只验登录态 + profile)
- Mac/Linux dev box
- 真 Android 设备
- APK 已 bundle in-APK cc + PDH ≥ 0.3.0
- 抓包工具 (Charles / mitmproxy) — 模拟 412 / token 过期
8 个 E2E 场景
场景 1 — 首次登录成功(happy path)
步骤:
- 打开 ChainlessChain → 个人数据中台 → 本机数据 tab
- 看到"今日头条"卡片,状态"未登录"
- 点"登录"→ WebView 加载
https://www.toutiao.com/(banner 推一键登录) - 用真账号登录 (短信 / 一键)
- WebView 跳到
www.toutiao.com主页 → ChainlessChain 命中 isLoginSuccess - 提取 cookie + 调
/passport/account/info/v2/?aid=24拿 user_id + screen_name → 关 WebView
断言:
- WebView 在登录后 ≤ 3s 内自动关闭
- 卡片状态变"已登录
<nickname>" pdh_social_toutiaoEncryptedSharedPreferences 中cookie/uid/displayName全非空- cookie 中
passport_uid(或multi_sids首段) 字段存在
场景 2 — 同步 profile 成功
前置: 场景 1 已完成
步骤:
- 在卡片点"同步"
- ~2-5s 后 (单 endpoint),toast "social-toutiao 同步完成 (+1 事件)"
- 卡片显示"上次同步: <时间>"
- banner 文本提示"已同步账号 profile(v0.2 含昵称/头像/粉丝数)。历史/收藏/搜索需 v0.3 _signature 签名接通。"
断言:
+1是 profile event (KIND_PROFILE)- vault 中可见
person-toutiao-<uid>记录 - person.identifiers 含
toutiao-uid+ 可选toutiao-media-id - person.extra 含 followingCount / followerCount / avatarUrl / description / mobile (passport endpoint 不返 counts,应为 0)
场景 3 — Cookie 过期 (status_code != 0)
前置: 已登录,cookie sessionid 失效
模拟:
adb shell run-as com.chainlesschain.android rm -rf app_webview/Cookies*- 或 Charles 拦 passport endpoint 返
{"status_code":2154,"status_msg":"session expired"}
步骤:
- 点"同步"
断言:
- profile 返 null,lastErrorCode = 2154
- 卡片显示"登录已过期 — code=2154 session expired (请重新登录)"
- 点"退出登录"清除本地 store
场景 4 — 反爬 412 (anti-spider)
模拟:
- Charles 拦 passport endpoint 返 HTTP 412 + body "blocked"
- 或缺 ttwid cookie / UA 非桌面 Chrome 触发真 412
步骤:
- 点"同步"
断言:
- profile 返 null,lastErrorCode = 412
- 卡片显示"风控触发 — code=412 HTTP 412 (请稍后或换网络重试)"
- 不清 store (cookie 可能仍有效)
场景 5 — WebView 取消登录
步骤:
- 全新装 APK
- 点"登录"进 WebView
- 在头条登录页不操作,按系统返回键
断言:
- WebView 关闭返回卡片列表
- 状态仍"未登录"
- 无 toast,无 errorMessage
- store 中 cookie / uid 字段空
场景 6 — 反复同步幂等性
前置: 已登录 + 已同步过一次
步骤:
- 立即再点"同步"
- 再点一次
断言:
- 三次 sync 后
vault.queryPersons()数量不变 (同 uid 走 UPSERT) - person.extra.snapshottedAt 每次更新
- person.names 不变 (除非用户改了昵称)
- raw_events 表只有 1 行 (profile originalId 是
toutiao:profile:<uid>)
场景 7 — EncryptedSharedPreferences keystore corruption
模拟: 改 pdh_social_toutiao.xml 让 AES-256-GCM 解密失败
步骤:
adb shell进 app data dir,备份 xml- 手改 1 byte
- 重启 app
断言:
- App 不 crash
- 头条卡片显"未登录"
- Timber log 含 "ToutiaoCredentialsStore: read failed"
- 用户能重新登录恢复
场景 8 — 退出登录 + 重新登录
步骤:
- 已登录点"退出登录"
- 卡片状态变"未登录"
- 点"登录"重登同一账号
- 同步
断言:
- 退出后 store 中 cookie / uid / displayName 全空
- 重新登录 uid 同上次
- 同步成功,person 记录同 ID (走 UPSERT 不是新建)
执行方式
- 手动: 按 8 场景逐一跑,每个 ~3-8 分钟,总 ~1h
- 自动化: 暂不可 (头条登录需短信 / 一键 / 扫码)
- CI: 仅跑场景 5 + 7 (非真账号);其余手动
v0.3 待补 (_signature 签名接通后)
/api/news/feed/v90/?category=__all__推荐流 — 新 E2E 场景: events 含 BROWSE 子类/article/v2/tab_comments/收藏 — 新 E2E 场景: events 含 LIKE 子类/api/search/content/搜索历史 — 新 E2E 场景: events 含 POST/SEARCH 子类- _signature 漂移 (acrawler.js obfuscate rotate) — 同 Douyin X-Bogus 模式
反爬 caveats
- 412 是 IP-based,单设备触发后影响整设备同一 IP 5-15 分钟
- ttwid 是 device fingerprint 长期不变;缺它直接 412
- passport endpoint 比 _signature 端点宽松,但仍要桌面 Chrome UA + Referer www.toutiao.com
stub 占位
androidTest/.../A8ToutiaoE2ETest.kt 8 个测试方法已 @Ignore 占位。
关联文档
docs/design/A8_Douyin_E2E_Plan.md— 同 v0.2 profile-only 模板基线 (aid=2906 vs aid=24 差异)- memory
pdh_social_collector_test_gap_audit.md— 6 platform 测试覆盖审计 - memory
pdh_social_webview_deeplink_cookie_capture.md— WebView 一键登录 deep-link 协议
附录:规范章节补全(v5.0.3.108)
本文为真机 E2E 测试计划。为对齐项目文档标准结构,下列章节以
见正文指引或简述方式补齐若干视角,不重复正文场景。
1. 概述
见正文「范围」。A8 今日头条 v0.3 真机 E2E 测试计划,覆盖 profile(passport aid=24)+ feed 采集(需 _signature),共 8 个场景。
2. 核心特性
8 个 E2E 场景;ToutiaoSignBridge(hidden WebView 跑 acrawler.js 取 _signature);ApiClient 3 endpoint;JVM 单测已通。
3. 系统架构
见 Adapter_Social_Cookie.md(A8 通用设计);profile 走 unsigned passport endpoint、feed 走 _signature 签名。
4. 系统定位
A8 今日头条 adapter 的真机 E2E 验收计划(v0.3 签名 surface,三家 v0.3 模板)。
5. 核心功能
见正文「8 个 E2E 场景」(登录 / 同步 profile / cookie 过期 / 反爬 412 / WebView 取消 / 幂等 / keystore / 退登重登)。
6. 技术架构
cookie + _signature(acrawler.js);profile /passport/account/info/v2/?aid=24、feed /api/news/feed/v90/;stub A8ToutiaoE2ETest.kt。
7. 系统特点
Win dev box 跑 JVM 单测 ✅(ToutiaoApiClientV03Test 等),真机 E2E 需 Mac/Linux + 真机 + 真账号。
8. 应用场景
adapter 上线前真机验收(含 _signature 接通后的 feed)。
9. 竞品对比
与 A8_Douyin_E2E_Plan.md(aid=2906 vs aid=24 差异)、A8_Kuaishou_E2E_Plan.md 同套 v0.3 模板。
10. 配置参考
见正文「前置(一次性)」与「v0.3 待补(_signature 签名接通后)」。
11. 性能指标
见正文「反爬 caveats」(412 反爬、签名稳定性);性能单独 perf plan。
12. 测试覆盖
本文即测试覆盖:8 个 E2E 场景 + JVM 单测(已通);E2E stub @Ignore 占位。
13. 安全考虑
场景 7 EncryptedSharedPreferences keystore corruption;cookie + 签名高敏感。
14. 故障排除
见正文异常场景:cookie 过期 status_code≠0(场景 3)、反爬 412(场景 4)、WebView 取消(场景 5)。
15. 关键文件
androidTest A8ToutiaoE2ETest.kt;ToutiaoSignBridge / ToutiaoApiClient。
16. 使用示例
见正文「执行方式」。
17. 相关文档
见正文「关联文档」:A8_Douyin_E2E_Plan.md、memory pdh_social_collector_test_gap_audit.md、pdh_social_webview_deeplink_cookie_capture.md。
