用户要求:"把你每一步操作都放出来让我自己写,你都封在一起我也不知道切号/认号的流程"
→ 把两个打包步骤的内部动作,拆成**画布上拖得出来的普通步骤**(能拆是因为补了下面两个零件)。
① 选择器值里的**变量**(tasks/generic/task.py `_vars_sub`)
`{本次要发的名字}`(循环块设的)/ `{本机账号名字}`(读名字读到的),中文别名与变量名都认。
用在 click / long_click / wait_el / swipe_until / expect_el / read_text / read_account_name /
switch_account 的选择器值,以及 if_el 的选择器与手填候选值。
· 没写花括号的步骤一个字不改(老任务零影响)
· 变量为空 → **换成空串 + 记警告**:宁可"选择器变空、找不到元素"明着报,
也不留 `{…}` 字面量去点到歪的地方
· 不做通用表达式(只认表里那几个名字)
② 「点击元素」的选择器类型下拉补上 **textContains**(文本包含)——
以前只能用打包步骤做到的"按名字点列表那一行",现在自己就能拼:
`textContains` + 值 `{本次要发的名字}`
③ 新步骤 **read_text「读取文字」**:把元素文字读出来存进指定变量
(`var`=account_name 时顺手把昵称控件记给切号/推送核对复用;`clean`=按账号名清洗/只去空白;
`on_missing`=skip 默认只记一句 / fail 算失败)。之前**没有**"读取元素文字"这种步骤。
④ 「条件判断」的候选值来源加 **「变量」**(`cmp_source=var` + `cmp_var`)——
不然 read_text 读出来的东西没处用。空变量 = 候选为空 = 不命中(同"读不到名字"的规矩)。
⑤ fix(发布) 实测踩出来的两处(A06,截图/日志为证):
· **剪辑页校验 12 → 45 秒**:点完「下一步」抖音在「正在导入」(一条 25 秒的视频要导 25 秒+),
导入期间工具栏不渲染,10~12 秒必然判"没到剪辑页"→ 这一条白发
· **切号前先回主界面**(`_goto_me`):点不到「我」页签 = 不在主界面(剪辑页/发布页),
那种页面没有底部页签 → **强杀 + 冷启动**抖音再来。实测卡在剪辑页时,本轮剩下的号全部报废
· **切号后回读为空时点一次「我」再读**:换号会整体重启抖音、起来常落在首页(首页没有昵称控件),
读多少次都是空 —— 等完 wait_after、读两遍仍空才补这一下导航,不打扰它的重启过程
前端:编辑器调色板/字段面板认 read_text(含变量说明)、选择器类型加 textContains、
placeholder 提示 `{本次要发的名字}`、候选值来源加「变量」+ 变量名输入、
「发布计划」页就地编辑字段表同步(release.js)。
文档:TASK_DEV §3 步骤表 28→29 种 + §3.3「选择器里的变量」+ §3.4「自己拼切号+认号」;
API.md 骨架步数修正(18 → 4 步 / 含嵌套 23 步)。
测试:新增 scripts/tests/test_read_text.py(变量代入、空变量不许瞎点、读取文字存变量/清洗、
条件判断取变量、草稿校验),全套 8 个用例通过。
50 lines
2.3 KiB
Python
50 lines
2.3 KiB
Python
"""发布计划「按名字发」相关用例:一次跑完,汇总结果。
|
||
|
||
用法(项目根目录):
|
||
.venv/Scripts/python scripts/tests/run_all.py # Windows
|
||
.venv/bin/python scripts/tests/run_all.py # Linux/macOS
|
||
|
||
这些用例的**铁律**(与 doc/DEVELOPMENT.md 的测试约定一致):
|
||
· 一律**临时 SQLite + 临时目录**(`DATABASE_URL` / `DATA_VIDEO_DIR` 指向 tempfile 建的目录),
|
||
**绝不碰用户的真实库与真实素材目录**;
|
||
· 需要设备的地方一律用**假设备**(桩对象/stub),**不连真机、不下发 adb**;
|
||
· 每个用例自己退出码非 0 表示失败,本脚本据此汇总。
|
||
|
||
覆盖:
|
||
test_parse_name 文件名/标题行解析(`名字_日期_编号`、`标题 || 正文_...`、各种拒收)
|
||
test_upload_name 上传 + 配标题落库(不再依赖任何账号台账)
|
||
test_name_scope 读本机账号名字、按名字取计划、推送前核对
|
||
test_switch_account 切换账号(按名字点控件、回读校验、登录页停设备)
|
||
test_foreach_account 循环本机待发的号(一轮跑完、试过不回头、干净退出)
|
||
test_push_by_name 按名字找设备推送(matched/unmatched、缓存)
|
||
test_expect_el 「校验页面」:特征在就过;不在就按 on_missing 处置(默认跳过本轮剩余步骤)
|
||
test_read_text 「读取文字」+ 选择器里的 {变量} +「条件判断→变量」
|
||
"""
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
CASES = ["test_parse_name.py", "test_upload_name.py", "test_name_scope.py",
|
||
"test_switch_account.py", "test_foreach_account.py", "test_push_by_name.py",
|
||
"test_expect_el.py", "test_read_text.py"]
|
||
|
||
if hasattr(sys.stdout, "reconfigure"):
|
||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||
|
||
failed = []
|
||
for name in CASES:
|
||
print("=" * 66)
|
||
print("▶", name)
|
||
print("=" * 66)
|
||
r = subprocess.run([sys.executable, os.path.join(HERE, name)])
|
||
if r.returncode != 0:
|
||
failed.append(name)
|
||
|
||
print()
|
||
print("=" * 66)
|
||
if failed:
|
||
print("❌ 失败 %d / %d:%s" % (len(failed), len(CASES), "、".join(failed)))
|
||
sys.exit(1)
|
||
print("✅ 全部 %d 个用例通过" % len(CASES))
|