提交 a63d090c authored 作者: 陈泽健's avatar 陈泽健

fix(executor): 直达导航接入 _do_navigate + micro-app reload 兜底 — 薄弱模块 31 用例 R7 通过率 100%

- _navigate_to_target_page 弃用裸 goto,改走 _do_navigate 完整路径
  (跨微应用 warm-up + _goto_full_page + _ensure_micro_app_loaded + _verify_micro_app_stable)
- _ensure_micro_app_loaded 新增阶段4 reload 兜底:body 为 NO-BODY 时
  page.reload()(探测证明 localStorage 方案 A/B/C 全部失败,reload 唯一有效)
- 14 个薄弱模块用例步骤断言对齐(monitor 9 + 消息通知 3 + 信息窗 1 + 通讯录 1)
- 沉淀 5 个探测/复刻脚本至 backend/scripts/
- R7 执行 exec_111da3930d734bc7a4a2ea009336558f:31/31 通过 100%,799.7s
- 同步更新 HANDOFF_UI自动化.md(会话 39/38 记录)
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 f4892d6c
此差异已折叠。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
probe_cross_case_monitor.py — 复刻 executor 跨用例场景:
登录 → 预热 ALARM → Home → 预热 FILE → Home → 预热 ALARM,
验证「第二次 monitor 导航」是否出现 micro-app NO-BODY(跨用例状态污染)。
"""
import sys
from playwright.sync_api import sync_playwright
sys.stdout.reconfigure(encoding='utf-8')
TARGET_URL = "https://192.168.5.44"
USERNAME = "admin@xty"
PASSWORD = "Ubains@13579"
CAPTCHA = "csba"
HOME_URL = TARGET_URL + "/#/platform?platform=%2Fplatform%2F%23%2FHome"
URL_ALARM = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Falarm%2FMaintenancelist"
URL_FILE = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Fmanage%2FFilemanage"
def login(page):
page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(3000)
for inp in page.query_selector_all('input:visible'):
ph = inp.get_attribute('placeholder') or ''
t = inp.get_attribute('type') or ''
if '手机' in ph or '用户' in ph or '邮箱' in ph:
inp.fill(USERNAME)
elif t == 'password':
inp.fill(PASSWORD)
elif '验证' in ph:
inp.fill(CAPTCHA)
for btn in page.query_selector_all('button'):
if '登录' in (btn.inner_text() or '').strip() and btn.is_visible():
btn.click()
break
page.wait_for_timeout(5000)
try:
page.wait_for_selector('.el-dialog:visible', timeout=5000)
for dlg in page.query_selector_all('.el-dialog'):
if not dlg.is_visible():
continue
for cb in dlg.query_selector_all('.el-checkbox__original'):
try:
if cb.is_visible() and not cb.is_checked():
cb.click()
except Exception:
pass
for btn in dlg.query_selector_all('button'):
if '确定' in (btn.inner_text() or '') and btn.is_visible():
btn.click()
break
page.wait_for_timeout(2000)
except Exception:
pass
page.wait_for_selector('.block', timeout=15000)
print("✓ 登录成功", flush=True)
def dump(page, tag):
try:
info = page.evaluate("""() => {
const out = {bodyOwn: 0, bodies: 0};
const bs = document.querySelectorAll('micro-app');
out.bodyOwn = bs.length;
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
out.bodies++;
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
out.tables = (out.tables||0) + root.querySelectorAll('.el-table').length;
out.rows = (out.rows||0) + root.querySelectorAll('.el-table__row').length;
}
}
return out;
}""")
print(f" [{tag}] URL={page.url[:85]} micro-app={info.get('bodyOwn')} body={info.get('bodies')} tables={info.get('tables')} rows={info.get('rows')}", flush=True)
except Exception as e:
print(f" [{tag}] 异常: {e}", flush=True)
def monitor_nav(page, url, tag):
print(f"\n-- {tag} 二段式 warm-up --", flush=True)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'doorScreenPublish', path: '/Backend/MediaPublish/MaterialManage'}));
localStorage.setItem('pageOpen', 'true');
localStorage.setItem('monitorLoginType', '2');
localStorage.setItem('address', 'https://192.168.5.44:8000');
localStorage.setItem('selectGroup', '0');
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'monitoring', path: '/monitoring/Monitoringindex'}));
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(6000)
dump(page, tag)
def to_home(page):
print(f"\n-- 回 Home --", flush=True)
try:
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
dump(page, "Home")
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
login(page)
monitor_nav(page, URL_ALARM, "第1次 ALARM")
to_home(page)
monitor_nav(page, URL_FILE, "第2次 FILE")
to_home(page)
monitor_nav(page, URL_ALARM, "第3次 ALARM")
browser.close()
print("\n✅ 完成", flush=True)
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
probe_failing_assert_targets.py — 针对 R6 失败断言,逐一验证选择器是否命中。
"""
import sys, json
from playwright.sync_api import sync_playwright
sys.stdout.reconfigure(encoding='utf-8')
TARGET_URL = "https://192.168.5.44"
USERNAME = "admin@xty"
PASSWORD = "Ubains@13579"
CAPTCHA = "csba"
URLS = {
"materialList": "https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FmaterialList",
"Meetingmaintenance": "https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FMeetingmaintenance",
"NotificationMessage": "https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FNotificationMessage",
"UserList": "https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FUserList",
}
def login(page):
page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(3000)
for inp in page.query_selector_all('input:visible'):
ph = inp.get_attribute('placeholder') or ''
t = inp.get_attribute('type') or ''
if '手机' in ph or '用户' in ph or '邮箱' in ph:
inp.fill(USERNAME)
elif t == 'password':
inp.fill(PASSWORD)
elif '验证' in ph:
inp.fill(CAPTCHA)
for btn in page.query_selector_all('button'):
if '登录' in (btn.inner_text() or '').strip() and btn.is_visible():
btn.click()
break
page.wait_for_timeout(5000)
try:
page.wait_for_selector('.el-dialog:visible', timeout=5000)
for dlg in page.query_selector_all('.el-dialog'):
if not dlg.is_visible():
continue
for cb in dlg.query_selector_all('.el-checkbox__original'):
try:
if cb.is_visible() and not cb.is_checked():
cb.click()
except Exception:
pass
for btn in dlg.query_selector_all('button'):
if '确定' in (btn.inner_text() or '') and btn.is_visible():
btn.click()
break
page.wait_for_timeout(2000)
except Exception:
pass
page.wait_for_selector('.block', timeout=15000)
print("✓ 登录成功", flush=True)
def test_selectors(page, name, url, selectors):
print(f"\n{'#'*50}\n# {name}\n{'#'*50}", flush=True)
page.goto(url, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(8000)
print(f"URL={page.url[:120]}", flush=True)
# micro-app content dump
info = page.evaluate("""() => {
const out = {};
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
out.bodyCount = (out.bodyCount||0) + 1;
out.tables = (out.tables||0) + root.querySelectorAll('.el-table').length;
out.rows = (out.rows||0) + root.querySelectorAll('.el-table__row').length;
out.text = (root.textContent||'').replace(/\\s+/g,' ').trim().slice(0,400);
const tabs = root.querySelectorAll('.el-tabs__item, .el-tab-pane');
out.tabs = Array.from(tabs).slice(0,10).map(t => (t.innerText||'').trim()).filter(Boolean);
const inputs = root.querySelectorAll('input');
out.inputs = Array.from(inputs).slice(0,8).map(i => (i.getAttribute('placeholder')||'val:'+i.value).slice(0,40));
}
}
return out;
}""")
print(f" micro-bodies={info.get('bodyCount')} tables={info.get('tables')} rows={info.get('rows')}", flush=True)
if info.get('tabs'):
print(f" tabs={info['tabs']}", flush=True)
if info.get('inputs'):
print(f" inputs={info['inputs'][:6]}", flush=True)
# Test each selector
for sel in selectors:
try:
page.wait_for_selector(sel, timeout=5000, state='attached')
print(f" ✅ {sel}", flush=True)
except Exception:
print(f" ❌ {sel}", flush=True)
# Also test via micro-app evaluate
print(f" body_text[:200]={info.get('text','')[:200]!r}", flush=True)
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
login(page)
test_selectors(page, "信息窗管理 materialList", URLS["materialList"], [
".el-table",
".el-table__row",
"input[placeholder*='请输入素材名称']",
"body:has-text('素材库')",
"body:has-text('节目管理')",
])
test_selectors(page, "工单列表 Meetingmaintenance", URLS["Meetingmaintenance"], [
".el-table",
".el-table__row",
"body:has-text('工单列表')",
"body:has-text('我的工单')",
"body:has-text('终端列表')",
"body:has-text('当前告警')",
])
test_selectors(page, "消息通知 NotificationMessage", URLS["NotificationMessage"], [
".el-table",
".el-table__row",
"body:has-text('全部信息')",
"body:has-text('我预约的')",
"body:has-text('我受邀的')",
"body:has-text('系统消息')",
".el-select",
])
test_selectors(page, "通讯录 UserList", URLS["UserList"], [
".el-table",
".el-table__row",
"body:has-text('退出')",
"body:has-text('默认部门名称')",
"body:has-text('优本技术')",
".el-tree",
"button:has-text('退出')",
])
browser.close()
print("\n✅ 完成", flush=True)
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
probe_monitor_remount.py — 第2次 monitor 导航 body=0 复现后,
测试4种恢复方案:A) 删 pageOpen B) pageOpen=false C) 清全部 monitor 键 D) reload
"""
import sys
from playwright.sync_api import sync_playwright
sys.stdout.reconfigure(encoding='utf-8')
TARGET_URL = "https://192.168.5.44"
USERNAME = "admin@xty"
PASSWORD = "Ubains@13579"
CAPTCHA = "csba"
HOME_URL = TARGET_URL + "/#/platform?platform=%2Fplatform%2F%23%2FHome"
URL_ALARM = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Falarm%2FMaintenancelist"
URL_FILE = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Fmanage%2FFilemanage"
def login(page):
page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(3000)
for inp in page.query_selector_all('input:visible'):
ph = inp.get_attribute('placeholder') or ''
t = inp.get_attribute('type') or ''
if '手机' in ph or '用户' in ph or '邮箱' in ph:
inp.fill(USERNAME)
elif t == 'password':
inp.fill(PASSWORD)
elif '验证' in ph:
inp.fill(CAPTCHA)
for btn in page.query_selector_all('button'):
if '登录' in (btn.inner_text() or '').strip() and btn.is_visible():
btn.click()
break
page.wait_for_timeout(5000)
try:
page.wait_for_selector('.el-dialog:visible', timeout=5000)
for dlg in page.query_selector_all('.el-dialog'):
if not dlg.is_visible():
continue
for cb in dlg.query_selector_all('.el-checkbox__original'):
try:
if cb.is_visible() and not cb.is_checked():
cb.click()
except Exception:
pass
for btn in dlg.query_selector_all('button'):
if '确定' in (btn.inner_text() or '') and btn.is_visible():
btn.click()
break
page.wait_for_timeout(2000)
except Exception:
pass
page.wait_for_selector('.block', timeout=15000)
print("✓ 登录成功", flush=True)
def dump(page, tag):
try:
info = page.evaluate("""() => {
const out = {bodies: 0};
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
out.bodies++;
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
out.tables = (out.tables||0) + root.querySelectorAll('.el-table').length;
out.rows = (out.rows||0) + root.querySelectorAll('.el-table__row').length;
}
}
return out;
}""")
print(f" [{tag}] URL={page.url[30:100]} body={info.get('bodies')} tables={info.get('tables')} rows={info.get('rows')}", flush=True)
return info.get('bodies', 0) > 0
except Exception as e:
print(f" [{tag}] 异常: {e}", flush=True)
return False
def warmup_and_goto(page, url, pre_fix_js, tag):
# 标准 warm-up(阶段1 backstage navPayload)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'doorScreenPublish', path: '/Backend/MediaPublish/MaterialManage'}));
localStorage.setItem('pageOpen', 'true');
localStorage.setItem('monitorLoginType', '2');
localStorage.setItem('address', 'https://192.168.5.44:8000');
localStorage.setItem('selectGroup', '0');
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
# 修复方案注入点 + 阶段2 monitor navPayload
if pre_fix_js:
page.evaluate(pre_fix_js)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'monitoring', path: '/monitoring/Monitoringindex'}));
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(6000)
return dump(page, tag)
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
login(page)
# 先做一次成功的 monitor 导航
warmup_and_goto(page, URL_ALARM, None, "第1次 ALARM(基准)")
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
page.wait_for_timeout(3000)
print(" (回 Home)", flush=True)
# 方案A:阶段2 前 删除 pageOpen
okA = warmup_and_goto(page, URL_FILE, "localStorage.removeItem('pageOpen')", "A: removeItem pageOpen→FILE")
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
page.wait_for_timeout(3000)
# 方案B:阶段2 前 pageOpen=false
okB = warmup_and_goto(page, URL_FILE, "localStorage.setItem('pageOpen','false')", "B: pageOpen=false→FILE")
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
page.wait_for_timeout(3000)
# 方案C:阶段2 前清全部 monitor 键再重设 navPayload
okC = warmup_and_goto(page, URL_FILE, """() => {
for (const k of ['pageOpen','monitorLoginType','address','selectGroup','navPayload']) localStorage.removeItem(k);
}""", "C: 清全部键→FILE")
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
page.wait_for_timeout(3000)
# 方案D:阶段2 goto 后 reload
okD1 = warmup_and_goto(page, URL_FILE, None, "D: goto→FILE(预期失败)")
try:
page.reload(wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(6000)
okD = dump(page, "D: reload 后")
page.goto(HOME_URL, wait_until="domcontentloaded", timeout=15000)
page.wait_for_timeout(3000)
print(f"\n结果: A(removeItem)={'✅' if okA else '❌'} B(false)={'✅' if okB else '❌'} C(清全部)={'✅' if okC else '❌'} D(reload)={'✅' if okD else '❌'}", flush=True)
browser.close()
print("\n✅ 完成", flush=True)
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
probe_monitor_sidebar.py — monitor 微应用加载后(设备列表页),通过其内部
侧边栏真实点击 素材管理/终端管理/设备列表/远程控制,探测是否存在
文件管理/下载列表等真实内容页(monitor 忽略 URL 内层路由,但点击导航可能有效)。
"""
import sys, time, urllib.parse as up
from playwright.sync_api import sync_playwright
sys.stdout.reconfigure(encoding='utf-8')
TARGET_URL = "https://192.168.5.44"
USERNAME = "admin@xty"
PASSWORD = "Ubains@13579"
CAPTCHA = "csba"
URL_ALARM = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Falarm%2FMaintenancelist"
def login(page):
page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(3000)
for inp in page.query_selector_all('input:visible'):
ph = inp.get_attribute('placeholder') or ''
t = inp.get_attribute('type') or ''
if '手机' in ph or '用户' in ph or '邮箱' in ph:
inp.fill(USERNAME)
elif t == 'password':
inp.fill(PASSWORD)
elif '验证' in ph:
inp.fill(CAPTCHA)
for btn in page.query_selector_all('button'):
if '登录' in (btn.inner_text() or '').strip() and btn.is_visible():
btn.click()
break
page.wait_for_timeout(5000)
try:
page.wait_for_selector('.el-dialog:visible', timeout=5000)
for dlg in page.query_selector_all('.el-dialog'):
if not dlg.is_visible():
continue
for cb in dlg.query_selector_all('.el-checkbox__original'):
try:
if cb.is_visible() and not cb.is_checked():
cb.click()
except Exception:
pass
for btn in dlg.query_selector_all('button'):
if '确定' in (btn.inner_text() or '') and btn.is_visible():
btn.click()
break
page.wait_for_timeout(2000)
except Exception:
pass
page.wait_for_selector('.block', timeout=15000)
print("✓ 登录成功", flush=True)
def dump_micro(page, tag):
try:
info = page.evaluate("""() => {
const out = [];
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
out.push({
tables: root.querySelectorAll('.el-table').length,
rows: root.querySelectorAll('.el-table__row').length,
headers: Array.from(root.querySelectorAll('.el-table__header th')).map(t => (t.innerText||'').trim()).filter(Boolean).join('|'),
text: (root.textContent||'').replace(/\\s+/g,' ').trim().slice(0,200)
});
}
}
return out;
}""")
except Exception as e:
print(f" [{tag}] evaluate 异常: {e}", flush=True)
return
print(f" [{tag}] URL={page.url[:90]}", flush=True)
for o in info:
print(f" tables={o['tables']} rows={o['rows']}", flush=True)
if o['headers']:
print(f" headers={o['headers'][:120]}", flush=True)
print(f" text={o['text']!r}", flush=True)
CLICK_JS = """(label) => {
const norm = s => (s || '').replace(/[\\s\\u00a0]+/g, ' ').trim();
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
const cands = [];
for (const el of root.querySelectorAll('li, a, span, div, [class*=menu] *, [class*=nav] *')) {
if (norm(el.innerText) === label && el.getBoundingClientRect().width > 0) {
cands.push(el);
}
}
// 优先最内层
if (cands.length) {
const el = cands[cands.length - 1];
el.scrollIntoView({block: 'center'});
el.click();
return true;
}
}
}
return false;
}"""
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
login(page)
# 加载 monitor(二段式 warm-up 复刻 executor)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'doorScreenPublish', path: '/Backend/MediaPublish/MaterialManage'}));
localStorage.setItem('pageOpen', 'true');
localStorage.setItem('monitorLoginType', '2');
localStorage.setItem('address', 'https://192.168.5.44:8000');
localStorage.setItem('selectGroup', '0');
}""")
try:
page.goto(URL_ALARM, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'monitoring', path: '/monitoring/Monitoringindex'}));
}""")
try:
page.goto(URL_ALARM, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(6000)
dump_micro(page, "monitor 初始(设备列表)")
for label in ["素材管理", "终端管理", "设备列表", "远程控制", "告警", "工单"]:
ok = False
try:
ok = page.evaluate(CLICK_JS, label)
except Exception as e:
print(f" click {label} 异常: {e}", flush=True)
if ok:
print(f"\n✓ 点击侧边栏: {label}", flush=True)
page.wait_for_timeout(5000)
dump_micro(page, f"点击后 {label}")
# 点击后可能弹窗/表格变化,dump 主文档 .el-table 数量
try:
n = page.evaluate("() => document.querySelectorAll('.el-table').length")
print(f" 主文档 .el-table={n}", flush=True)
except Exception:
pass
else:
print(f"\n✗ 未找到可点击的 {label}", flush=True)
browser.close()
print("\n✅ 完成", flush=True)
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
probe_v3_monitor_stability.py — 检查两类导航稳定性:
A. meetingV3 Meetingmaintenance(工单列表/我的工单):3 个全新上下文各导航一次,
统计 5表/59行 是否稳定出现,还是偶发加载失败。
B. monitor(告警工单/文件列表):复刻 executor 二段式 warm-up + _ensure_micro_app_loaded
三阶段(含 hash 重置),在断言时点 dump .el-table 是否存在。
"""
import sys, time, urllib.parse as up
from playwright.sync_api import sync_playwright
sys.stdout.reconfigure(encoding='utf-8')
TARGET_URL = "https://192.168.5.44"
USERNAME = "admin@xty"
PASSWORD = "Ubains@13579"
CAPTCHA = "csba"
URL_WORKORDER = "https://192.168.5.44/#/meetingV3?meetingV3=%2FmeetingV3%2F%23%2FMeetingmaintenance"
URL_ALARM = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Falarm%2FMaintenancelist"
URL_FILE = "https://192.168.5.44/#/backend/monitor?monitor=%2Fmonitor%2F%23%2Fadminsystem%2Fmanage%2FFilemanage"
def login(page):
page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(3000)
for inp in page.query_selector_all('input:visible'):
ph = inp.get_attribute('placeholder') or ''
t = inp.get_attribute('type') or ''
if '手机' in ph or '用户' in ph or '邮箱' in ph:
inp.fill(USERNAME)
elif t == 'password':
inp.fill(PASSWORD)
elif '验证' in ph:
inp.fill(CAPTCHA)
for btn in page.query_selector_all('button'):
if '登录' in (btn.inner_text() or '').strip() and btn.is_visible():
btn.click()
break
page.wait_for_timeout(5000)
try:
page.wait_for_selector('.el-dialog:visible', timeout=5000)
for dlg in page.query_selector_all('.el-dialog'):
if not dlg.is_visible():
continue
for cb in dlg.query_selector_all('.el-checkbox__original'):
try:
if cb.is_visible() and not cb.is_checked():
cb.click()
except Exception:
pass
for btn in dlg.query_selector_all('button'):
if '确定' in (btn.inner_text() or '') and btn.is_visible():
btn.click()
break
page.wait_for_timeout(2000)
except Exception:
pass
page.wait_for_selector('.block', timeout=15000)
print("✓ 登录成功", flush=True)
def dump_micro(page, tag):
info = page.evaluate("""() => {
const out = [];
for (const b of document.querySelectorAll('micro-app micro-app-body')) {
const roots = [b];
if (b.shadowRoot) roots.push(b.shadowRoot);
for (const root of roots) {
out.push({
tables: root.querySelectorAll('.el-table').length,
rows: root.querySelectorAll('.el-table__row').length,
text: (root.textContent||'').replace(/\\s+/g,' ').trim().slice(0,120)
});
}
}
return out;
}""")
print(f" [{tag}] URL={page.url[:100]}", flush=True)
for o in info:
print(f" tables={o['tables']} rows={o['rows']} text={o['text']!r}", flush=True)
if not info:
print(" (无 micro-app-body)", flush=True)
def experiment_a(browser, tag):
print(f"\n{'#'*40}\n# A: meetingV3 Meetingmaintenance ×3 {tag}\n{'#'*40}", flush=True)
for i in range(3):
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
try:
login(page)
page.goto(URL_WORKORDER, wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(8000)
dump_micro(page, f"trial{i+1}")
except Exception as e:
print(f" trial{i+1} 异常: {type(e).__name__}: {str(e)[:120]}", flush=True)
finally:
page.close()
def extract_marker(url):
if "#" not in url:
return "", ""
original_hash = url.split("#", 1)[1]
outer = url.split("#", 1)[1]
qs_vals = []
for v in up.parse_qs(outer).values():
qs_vals.extend(v)
decoded = up.unquote(" ".join(qs_vals))
segs = [s for s in decoded.replace("%23", "#").replace("%2F", "/").split("/") if s]
marker = segs[-1] if segs else ""
return marker, original_hash
def experiment_b(browser, url, tag):
print(f"\n{'#'*40}\n# B: monitor 复刻 executor {tag}\n{'#'*40}", flush=True)
page = browser.new_page(ignore_https_errors=True, viewport={"width": 1920, "height": 1080})
login(page)
marker, original_hash = extract_marker(url)
# 二段式 warm-up
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'doorScreenPublish', path: '/Backend/MediaPublish/MaterialManage'}));
localStorage.setItem('pageOpen', 'true');
localStorage.setItem('monitorLoginType', '2');
localStorage.setItem('address', 'https://192.168.5.44:8000');
localStorage.setItem('selectGroup', '0');
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
page.evaluate("""() => {
localStorage.setItem('navPayload', JSON.stringify({list: 'monitoring', path: '/monitoring/Monitoringindex'}));
}""")
try:
page.goto(url, wait_until="domcontentloaded", timeout=15000)
except Exception:
pass
page.wait_for_timeout(3000)
# _ensure_micro_app_loaded 阶段1轮询 5s
print(" 阶段1: 轮询 marker 就绪...", flush=True)
deadline = time.time() + 5
while time.time() < deadline:
body = page.query_selector("micro-app micro-app-body")
body_text = body.inner_text()[:80] if body else "NO-BODY"
has_marker = marker in page.url if marker else True
if has_marker and body and "加载中" not in body_text and "欢迎使用" not in body_text:
print(f" 阶段1 就绪 marker_in_url={has_marker}", flush=True)
break
page.wait_for_timeout(1000)
# 阶段2 hash 重置
if marker and original_hash:
print(f" 阶段2: 重置 hash", flush=True)
page.evaluate(f'window.location.hash = "#{original_hash}"')
page.wait_for_timeout(2000)
# 阶段3 轮询
print(" 阶段3: 轮询 5s...", flush=True)
deadline = time.time() + 5
while time.time() < deadline:
body = page.query_selector("micro-app micro-app-body")
body_text = body.inner_text()[:80] if body else "NO-BODY"
has_marker = marker in page.url if marker else True
if has_marker and body and "加载中" not in body_text and "欢迎使用" not in body_text:
print(f" 阶段3 就绪", flush=True)
break
page.wait_for_timeout(1000)
page.wait_for_timeout(500)
dump_micro(page, "断言时点")
# 主页面直接查 .el-table(executor element_exists 的路径)
try:
n = page.evaluate("() => document.querySelectorAll('.el-table').length")
print(f" 主文档 .el-table={n}", flush=True)
except Exception as e:
print(f" 主文档查询异常: {e}", flush=True)
page.close()
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
experiment_a(browser, "")
experiment_b(browser, URL_ALARM, "ALARM(Maintenancelist)")
experiment_b(browser, URL_FILE, "FILE(Filemanage)")
browser.close()
print("\n✅ 完成", flush=True)
if __name__ == '__main__':
main()
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论