169 lines
6.2 KiB
JavaScript
169 lines
6.2 KiB
JavaScript
const fs = require('fs')
|
|
const path = require('path')
|
|
const WebSocket = require('ws')
|
|
|
|
const outputDir = path.resolve(__dirname, 'screenshots')
|
|
fs.mkdirSync(outputDir, { recursive: true })
|
|
const loginUser = process.env.MES_MANUAL_USER
|
|
const loginPassword = process.env.MES_MANUAL_PASSWORD
|
|
|
|
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
|
|
async function connect() {
|
|
const targets = await fetch('http://127.0.0.1:9222/json').then(res => res.json())
|
|
const target = targets.find(item => item.type === 'page')
|
|
if (!target) throw new Error('No Chrome page target found')
|
|
|
|
const ws = new WebSocket(target.webSocketDebuggerUrl)
|
|
let id = 0
|
|
const pending = new Map()
|
|
ws.on('message', raw => {
|
|
const message = JSON.parse(raw.toString())
|
|
if (message.id && pending.has(message.id)) {
|
|
const { resolve, reject } = pending.get(message.id)
|
|
pending.delete(message.id)
|
|
message.error ? reject(new Error(message.error.message)) : resolve(message.result)
|
|
}
|
|
})
|
|
await new Promise((resolve, reject) => {
|
|
ws.once('open', resolve)
|
|
ws.once('error', reject)
|
|
})
|
|
|
|
const send = (method, params = {}) => new Promise((resolve, reject) => {
|
|
const requestId = ++id
|
|
pending.set(requestId, { resolve, reject })
|
|
ws.send(JSON.stringify({ id: requestId, method, params }))
|
|
})
|
|
return { ws, send }
|
|
}
|
|
|
|
async function main() {
|
|
const { ws, send } = await connect()
|
|
await send('Page.enable')
|
|
await send('Runtime.enable')
|
|
await send('Emulation.setDeviceMetricsOverride', {
|
|
width: 1920,
|
|
height: 1080,
|
|
deviceScaleFactor: 1,
|
|
mobile: false
|
|
})
|
|
|
|
const evaluate = expression => send('Runtime.evaluate', {
|
|
expression,
|
|
awaitPromise: true,
|
|
returnByValue: true
|
|
}).then(result => result.result.value)
|
|
|
|
async function waitFor(expression, timeout = 30000) {
|
|
const started = Date.now()
|
|
while (Date.now() - started < timeout) {
|
|
if (await evaluate(`Boolean(${expression})`)) return
|
|
await wait(300)
|
|
}
|
|
throw new Error(`Timed out waiting for: ${expression}`)
|
|
}
|
|
|
|
async function screenshot(name) {
|
|
await wait(700)
|
|
const result = await send('Page.captureScreenshot', {
|
|
format: 'png',
|
|
captureBeyondViewport: false,
|
|
fromSurface: true
|
|
})
|
|
fs.writeFileSync(path.join(outputDir, `${name}.png`), Buffer.from(result.data, 'base64'))
|
|
console.log(`Captured ${name}`)
|
|
}
|
|
|
|
async function navigate(hashPath) {
|
|
await send('Page.navigate', { url: `https://127.0.0.1:1997/#${hashPath}` })
|
|
await waitFor("document.readyState === 'complete'")
|
|
await waitFor("document.querySelector('.app-main') || document.querySelector('.el-card')", 40000)
|
|
await wait(1800)
|
|
}
|
|
|
|
async function clickByText(text, selector = 'button') {
|
|
return evaluate(`(() => {
|
|
const nodes = [...document.querySelectorAll(${JSON.stringify(selector)})]
|
|
const node = nodes.find(item => item.innerText && item.innerText.replace(/\\s+/g, '').includes(${JSON.stringify(text.replace(/\s+/g, ''))}))
|
|
if (!node) return false
|
|
node.click()
|
|
return true
|
|
})()`)
|
|
}
|
|
|
|
await send('Page.navigate', { url: 'https://127.0.0.1:1997/#/login' })
|
|
await waitFor("document.querySelector('input[name=username]') || document.querySelector('.sidebar-container')", 40000)
|
|
if (await evaluate("Boolean(document.querySelector('input[name=username]'))")) {
|
|
if (!loginUser || !loginPassword) {
|
|
throw new Error('Set MES_MANUAL_USER and MES_MANUAL_PASSWORD before capturing pages')
|
|
}
|
|
await evaluate(`(() => {
|
|
const setValue = (el, value) => {
|
|
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set
|
|
setter.call(el, value)
|
|
el.dispatchEvent(new Event('input', { bubbles: true }))
|
|
el.dispatchEvent(new Event('change', { bubbles: true }))
|
|
}
|
|
setValue(document.querySelector('input[name=username]'), ${JSON.stringify(loginUser)})
|
|
setValue(document.querySelector('input[name=password]'), ${JSON.stringify(loginPassword)})
|
|
})()`)
|
|
await clickByText('登录')
|
|
}
|
|
await waitFor("document.querySelector('.sidebar-container')", 40000)
|
|
await wait(1500)
|
|
|
|
const pages = [
|
|
['01-personnel-list', '/SystemMaintenance/PersonnelManagement/index'],
|
|
['02-role-list', '/SystemMaintenance/SystemRrolemaintenance/index'],
|
|
['03-menu-list', '/SystemMaintenance/MenuManagement/index'],
|
|
['04-workstation-list', '/SystemMaintenance/WorkstationManagement/index'],
|
|
['05-operation-log', '/SystemMaintenance/OperationLog/index']
|
|
]
|
|
|
|
for (const [name, route] of pages) {
|
|
await navigate(route)
|
|
await screenshot(name)
|
|
|
|
if (name === '01-personnel-list') {
|
|
if (await clickByText('新增')) {
|
|
await waitFor("document.querySelector('.el-dialog__wrapper:not([style*=\"display: none\"])')")
|
|
await screenshot('01-personnel-add-dialog')
|
|
await clickByText('取消', '.el-dialog__wrapper:not([style*=\"display: none\"]) button')
|
|
}
|
|
}
|
|
if (name === '02-role-list') {
|
|
if (await clickByText('新增')) {
|
|
await waitFor("document.querySelector('.el-dialog__wrapper:not([style*=\"display: none\"])')")
|
|
await screenshot('02-role-add-dialog')
|
|
await clickByText('取消', '.el-dialog__wrapper:not([style*=\"display: none\"]) button')
|
|
}
|
|
}
|
|
if (name === '03-menu-list') {
|
|
await evaluate(`document.querySelector('#selectRoleName').click()`)
|
|
await waitFor("[...document.querySelectorAll('.el-select-dropdown__item')].some(item => item.innerText.trim() === '管理员')")
|
|
await evaluate(`(() => {
|
|
const option = [...document.querySelectorAll('.el-select-dropdown__item')]
|
|
.find(item => item.innerText.trim() === '管理员')
|
|
option.click()
|
|
})()`)
|
|
await waitFor("document.querySelectorAll('.moduleTree .el-tree-node').length > 0")
|
|
await screenshot('03-menu-permission-panel')
|
|
}
|
|
if (name === '04-workstation-list') {
|
|
if (await clickByText('新增')) {
|
|
await waitFor("document.querySelector('.el-dialog__wrapper:not([style*=\"display: none\"])')")
|
|
await screenshot('04-workstation-add-dialog')
|
|
await clickByText('取消', '.el-dialog__wrapper:not([style*=\"display: none\"]) button')
|
|
}
|
|
}
|
|
}
|
|
|
|
ws.close()
|
|
}
|
|
|
|
main().catch(error => {
|
|
console.error(error)
|
|
process.exitCode = 1
|
|
})
|