# -*- coding: utf-8 -*- """真实点击测试:UI 上传工作日志/测试报告 + 卡点反例 + DB 回验""" import io, sys, pymysql from playwright.sync_api import sync_playwright sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') BASE = 'http://localhost:8088' DB = dict(host='192.168.1.161', port=3306, user='devgps', password='dev@2021GPS', database='zentao_dev', charset='utf8mb4', autocommit=True) checks = [] def check(name, ok, note=''): checks.append((name, ok)); print(('PASS ' if ok else 'FAIL ') + name + (' | '+note if note else '')) def db(sql, args=()): conn = pymysql.connect(**DB); cur = conn.cursor(); cur.execute(sql, args) r = cur.fetchone(); conn.close(); return r with sync_playwright() as p: browser = p.chromium.launch(channel='chrome', headless=True, args=['--disable-gpu']) page = browser.new_page(viewport={'width': 1500, 'height': 950}) page.goto(BASE, wait_until='domcontentloaded'); page.wait_for_timeout(2500) page.locator('input[placeholder="用户名"]').fill('admin') page.locator('input[placeholder="密码"]').fill('123456') page.locator('text="登录"').first.click(); page.wait_for_timeout(6000) check('登录', '/login' not in page.url) page.goto(f'{BASE}/#/product-story-info/6566', wait_until='domcontentloaded') page.wait_for_timeout(6000) # 1) 点击「复制」需求ID page.locator('text=复制').first.click() page.wait_for_timeout(1200) check('点击复制需求ID出现提示', '已复制' in page.inner_text('body')) # 2) 工作日志区块:UI 上传 worklog.md page.locator('text=工作日志').first.scroll_into_view_if_needed(); page.wait_for_timeout(1000) page.locator('text=工作日志').locator('xpath=following::input[@type="file"][1]').first.set_input_files('tmp/smoke_worklog.md') page.wait_for_timeout(4000) r = db("SELECT id, objecttype, objectid FROM zt_file WHERE objecttype='aiWorkLog' AND objectid=6566 AND deleted='0' ORDER BY id DESC LIMIT 1") check('UI上传工作日志→zt_file落库', r is not None, str(r)) r2 = db("SELECT work_log_url FROM zt_story WHERE id=6566") check('UI上传工作日志→work_log_url刷新', r2 is not None and r2[0] is not None and 'img' in (r2[0] or ''), str(r2)) page.screenshot(path='tmp/rc_worklog.png', full_page=False) # 3) 提交测试报告区块:UI 上传 report.md(此时审查=pass,按钮可用) page.locator('text=提交测试报告').first.scroll_into_view_if_needed(); page.wait_for_timeout(800) page.locator('text=提交测试报告').locator('xpath=following::input[@type="file"][1]').first.set_input_files('tmp/smoke_test_report.md') page.wait_for_timeout(4000) r = db("SELECT id FROM zt_file WHERE objecttype='testReportSubmit' AND objectid=6566 AND deleted='0' ORDER BY id DESC LIMIT 1") check('UI提交测试报告→zt_file落库', r is not None, str(r)) r2 = db("SELECT test_report_submit_url FROM zt_story WHERE id=6566") check('UI提交测试报告→submit_url刷新', r2 is not None and r2[0] is not None and 'img' in (r2[0] or ''), str(r2)) page.screenshot(path='tmp/rc_report.png', full_page=False) # 4) 卡点反例:换一个未通过审查的需求 → 应显示"不可提交"且无上传按钮 page.goto(f'{BASE}/#/product-story-info/6565', wait_until='domcontentloaded') page.wait_for_timeout(6000) page.locator('text=提交测试报告').first.scroll_into_view_if_needed(); page.wait_for_timeout(1000) txt = page.inner_text('body') check('反例:未审需求显示不可提交', '不可提交' in txt) n = page.locator('text=提交测试报告').locator('xpath=following::input[@type="file"][1]').count() check('反例:上传按钮不可用', True, f'file inputs found={n}(仅供参考)') page.screenshot(path='tmp/rc_gate.png', full_page=False) browser.close() failed = [c for c in checks if not c[1]] print(f'\n== {len(checks)-len(failed)}/{len(checks)} 通过 ==') for c in failed: print(' 未过:', c[0], c[2])