# -*- coding: utf-8 -*- """真实点击测试②:UI 新建会议(type=story)+ 编辑弹窗上传 MD 纪要""" 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) page.goto(f'{BASE}/#/product-meeting/145', wait_until='domcontentloaded') page.wait_for_timeout(5000) page.screenshot(path='tmp/rc_meeting_list.png', full_page=False) # 打开新增弹窗(列表页右上蓝色「会议纪要」按钮) add_btn = page.locator('button.el-button--primary:has-text("会议纪要")').first check('会议列表-新增按钮存在', add_btn.count() > 0) add_btn.click() page.wait_for_timeout(2500) dlg = page.locator('.el-dialog:visible').last # 会议类型 → 需求会议(story)(第 2 个 select,第 1 个是禁用的所属产品) dlg.locator('.el-select').nth(1).click(); page.wait_for_timeout(1000) opt = page.locator('.el-select-dropdown:visible .el-select-dropdown__item:has-text("需求会议")').first opt.click(); page.wait_for_timeout(1500) # 时间 dp = dlg.locator('input[placeholder="选择日期"]').first dp.click(); page.wait_for_timeout(600) dp.fill('2026-07-28 15:00:00'); page.keyboard.press('Enter'); page.wait_for_timeout(800) # 地点 dlg.locator('.el-form-item:has-text("会议地点") input').fill('联调会议室') # 参会人(BaseUserSelect:点击后选第一个选项) try: dlg.locator('.el-form-item:has-text("参会人") .el-select, .el-form-item:has-text("参会人") input').first.click() page.wait_for_timeout(1500) page.locator('.el-select-dropdown:visible .el-select-dropdown__item').first.click() page.wait_for_timeout(800) except Exception as e: print('参会人选择跳过:', str(e)[:60]) page.keyboard.press('Escape'); page.wait_for_timeout(600) dlg.click(position={'x': 10, 'y': 10}); page.wait_for_timeout(500) # 主题 dlg.locator('.el-form-item:has-text("会议主题") input').fill('冒烟联调会议R1') # 三个必填富文本(讨论的内容/结果/后续行动) for label, content in [('讨论的内容', '联调内容:SOP 会议流验证'), ('讨论的结果', '结论:通过'), ('后续行动安排', '行动:无')]: ed = dlg.locator(f'.el-form-item:has-text("{label}") .ql-editor, .el-form-item:has-text("{label}") [contenteditable="true"]').first ed.click(); page.wait_for_timeout(400) ed.fill(content); page.wait_for_timeout(400) page.screenshot(path='tmp/rc_meeting_dialog.png', full_page=False) # 保存 save = dlg.locator('button:has-text("确 定")').first save.click(); page.wait_for_timeout(4000) r = db("SELECT id, title, type, users, address FROM zt_meeting WHERE title LIKE %s ORDER BY id DESC LIMIT 1", ('%冒烟联调%',)) check('UI新建会议→zt_meeting落库', r is not None, str(r)) mid = r[0] if r else None # 编辑弹窗上传 MD if mid: page.goto(f'{BASE}/#/product-meeting-info/{mid}', wait_until='domcontentloaded') page.wait_for_timeout(5000) edit = page.locator('button:has-text("编辑")').first edit.click(); page.wait_for_timeout(2500) inp = page.locator('input[type="file"]').first inp.set_input_files('tmp/smoke_worklog.md') page.wait_for_timeout(2000) save2 = page.locator('.el-dialog:visible button:has-text("确 定")').first save2.click(); page.wait_for_timeout(4000) r = db("SELECT id FROM zt_file WHERE objecttype='meeting' AND objectid=%s AND deleted='0' ORDER BY id DESC LIMIT 1", (mid,)) check('会议编辑上传MD→zt_file落库', r is not None, str(r)) r2 = db("SELECT url FROM zt_meeting WHERE id=%s", (mid,)) check('会议MD→zt_meeting.url刷新', r2 is not None and r2[0] is not None and 'img' in (r2[0] or ''), str(r2)) page.screenshot(path='tmp/rc_meeting_att.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])