import { chromium } from 'playwright-core' const BASE = 'http://localhost:5082' const chromePath = 'C:/Program Files/Google/Chrome/Application/chrome.exe' const seedStorage = ` sessionStorage.setItem('fms-login', JSON.stringify({ loginInfo: { token: 'probe-token', user: { id: 1, account: 'admin', name: '探针用户' } }, })); localStorage.setItem('fms-user', JSON.stringify({ userInfo: { orgId: 'PROBE', account: 'admin' } })); localStorage.setItem('app', JSON.stringify({ darkMode: false })); ` const browser = await chromium.launch({ executablePath: chromePath, headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu-sandbox'], }) const context = await browser.newContext({ viewport: { width: 1280, height: 800 } }) await context.addInitScript(seedStorage) const page = await context.newPage() page.on('pageerror', (e) => console.log('[pageerror]', String(e).slice(0, 400))) page.on('console', (m) => { if (/error/i.test(m.text())) console.log('[console.error]', m.text().slice(0, 300)) }) await page.goto(`${BASE}/dashboard`, { waitUntil: 'domcontentloaded' }) await page.waitForSelector('.fms-table') await page.waitForFunction(() => document.querySelectorAll('.stk-tbody-main tr').length > 0) await page.waitForTimeout(1200) // 目标 td 信息 + 点击点实际命中的元素 const info = await page.evaluate(() => { const root = document.querySelector('.fms-table') const trs = [...root.querySelectorAll('.stk-tbody-main tr')] const out = { trCount: trs.length, trClasses: trs.map((tr) => tr.className), firstTrHTML: trs[0]?.outerHTML.slice(0, 300), secondTrHTML: trs[1]?.outerHTML.slice(0, 300), } const td = trs[1]?.querySelector('td[data-col-key]') if (td) { const r = td.getBoundingClientRect() const hit = document.elementFromPoint(r.left + r.width / 2, r.top + r.height / 2) out.td = { colKey: td.getAttribute('data-col-key'), rect: { left: r.left, top: r.top, w: r.width, h: r.height }, hit: hit ? `${hit.tagName}.${hit.className}` : null, tdClass: td.className, inner: td.innerHTML.slice(0, 200), } } else { out.td = null } // StkTable 选区容器信息 const viewportEls = [...root.querySelectorAll('*')].filter( (el) => el.scrollHeight > el.clientHeight + 2, ) out.scrollers = viewportEls.map((el) => ({ cls: el.className, sh: el.scrollHeight, ch: el.clientHeight, })) return out }) console.log(JSON.stringify(info, null, 2)) // 用真实鼠标点击 const tdInfo = await page.evaluate(() => { const root = document.querySelector('.fms-table') const trs = root.querySelectorAll('.stk-tbody-main tr') const td = trs[1]?.querySelector('td[data-col-key]') if (!td) return null const r = td.getBoundingClientRect() return { x: r.left + r.width / 2, y: r.top + r.height / 2 } }) if (tdInfo) { console.log('\n点击坐标:', tdInfo) await page.mouse.click(tdInfo.x, tdInfo.y) await page.waitForTimeout(800) const after = await page.evaluate(() => { const root = document.querySelector('.fms-table') return { editors: root.querySelectorAll('.fms-cell-editor-root').length, editorInputs: root.querySelectorAll('.fms-cell-editor-root input').length, csSel: root.querySelectorAll('[data-cs-s]').length, selectedCells: root.querySelectorAll('.stk-cell-selected, [data-cs-s="selected"]').length, activeElement: document.activeElement ? `${document.activeElement.tagName}.${document.activeElement.className}` : null, } }) console.log('点击后状态:', JSON.stringify(after, null, 2)) } await browser.close()