接口开始5%
This commit is contained in:
@@ -1,4 +1,107 @@
|
||||
const sleep=(ms)=>new Promise(r=>setTimeout(r,ms));const origin=process.argv[2]||'http://localhost:5173';
|
||||
const connect=async()=>{const pages=await(await fetch('http://127.0.0.1:9222/json/list')).json();const page=pages.find(x=>x.type==='page'&&x.url.startsWith(`${origin}/`));if(!page)throw new Error('No application page');const socket=new WebSocket(page.webSocketDebuggerUrl);await new Promise((r,j)=>{socket.addEventListener('open',r,{once:true});socket.addEventListener('error',j,{once:true})});let id=0;const pending=new Map();socket.addEventListener('message',e=>{const m=JSON.parse(e.data),p=pending.get(m.id);if(!p)return;pending.delete(m.id);m.error?p.reject(new Error(m.error.message)):p.resolve(m.result)});const send=(method,params={})=>new Promise((resolve,reject)=>{id+=1;pending.set(id,{resolve,reject});socket.send(JSON.stringify({id,method,params}))});return{socket,send}}
|
||||
const valueOf=async(s,e)=>(await s('Runtime.evaluate',{expression:e,returnByValue:true})).result?.value;const waitFor=async(s,e,m)=>{for(let i=0;i<50;i+=1){if(await valueOf(s,e))return;await sleep(100)}throw new Error(m)};let auditId=0;const open=async(s,r,q,sel)=>{auditId+=1;const u=`${origin}/?audit=${auditId}#${r}${q}`;await s('Page.navigate',{url:u});await waitFor(s,`location.href === ${JSON.stringify(u)}`,'navigation failed');await waitFor(s,`Boolean(document.querySelector(${JSON.stringify(sel)}))`,`missing ${sel}`)};
|
||||
const run=async()=>{const{socket,send}=await connect();try{await send('Page.enable');await send('Runtime.enable');await open(send,'/pages/family/f01-family-feed','?genealogyId=1001','.feed-state--list');await open(send,'/pages/family/f02-publish-feed','?genealogyId=1001','.publish-state--form');await open(send,'/pages/notification/n01-message-center','','.notice-state--list');await open(send,'/pages/profile/m01-profile-home','','.profile-state--ready');await open(send,'/pages/family/f01-family-feed','?state=empty&genealogyId=1001','.feed-state--empty');await open(send,'/pages/family/f02-publish-feed','?state=success&genealogyId=1001','.publish-state--success');await open(send,'/pages/notification/n01-message-center','?state=empty','.notice-state--empty');await open(send,'/pages/profile/m01-profile-home','?state=error','.profile-state--error');process.stdout.write('ROOT-PAGES-RUNTIME-SMOKE PASS\n')}finally{socket.close()}};run().catch(e=>{process.stderr.write(`${e.stack||e.message}\n`);process.exit(1)})
|
||||
const origin = process.argv[2] || 'http://localhost:5173'
|
||||
const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds))
|
||||
|
||||
const connect = async () => {
|
||||
const pages = await (await fetch('http://127.0.0.1:9222/json/list')).json()
|
||||
const page = pages.find((item) => item.type === 'page' && item.url.startsWith(`${origin}/`))
|
||||
if (!page) throw new Error(`Chrome debugging has no ${origin} application page`)
|
||||
|
||||
const socket = new WebSocket(page.webSocketDebuggerUrl)
|
||||
await new Promise((resolve, reject) => {
|
||||
socket.addEventListener('open', resolve, { once: true })
|
||||
socket.addEventListener('error', reject, { once: true })
|
||||
})
|
||||
|
||||
let id = 0
|
||||
const pending = new Map()
|
||||
socket.addEventListener('message', (event) => {
|
||||
const message = JSON.parse(event.data)
|
||||
const request = pending.get(message.id)
|
||||
if (!request) return
|
||||
pending.delete(message.id)
|
||||
message.error ? request.reject(new Error(message.error.message)) : request.resolve(message.result)
|
||||
})
|
||||
|
||||
const send = (method, params = {}) => new Promise((resolve, reject) => {
|
||||
id += 1
|
||||
pending.set(id, { resolve, reject })
|
||||
socket.send(JSON.stringify({ id, method, params }))
|
||||
})
|
||||
|
||||
return { socket, send }
|
||||
}
|
||||
|
||||
const valueOf = async (send, expression) => {
|
||||
const result = await send('Runtime.evaluate', { expression, returnByValue: true })
|
||||
if (result.exceptionDetails) throw new Error(result.exceptionDetails.exception?.description || result.exceptionDetails.text)
|
||||
return result.result?.value
|
||||
}
|
||||
|
||||
const waitFor = async (send, expression, message) => {
|
||||
for (let attempt = 0; attempt < 60; attempt += 1) {
|
||||
try {
|
||||
if (await valueOf(send, expression)) return
|
||||
} catch (error) {
|
||||
if (!String(error.message).includes('Inspected target navigated or closed')) throw error
|
||||
}
|
||||
await sleep(100)
|
||||
}
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
let auditId = 0
|
||||
const open = async (send, route, query, selector) => {
|
||||
auditId += 1
|
||||
const url = `${origin}/?rootAudit=${auditId}#${route}${query}`
|
||||
await send('Page.navigate', { url })
|
||||
await waitFor(send, `location.href === ${JSON.stringify(url)}`, `Navigation failed: ${route}${query}`)
|
||||
await waitFor(send, `Boolean(document.querySelector(${JSON.stringify(selector)}))`, `Missing ${selector}: ${route}${query}`)
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
const { socket, send } = await connect()
|
||||
try {
|
||||
await send('Page.enable')
|
||||
await send('Runtime.enable')
|
||||
|
||||
// 步骤一:四个根入口必须能进入各自默认状态,继续承担基础路由与渲染冒烟职责。
|
||||
await open(send, '/pages/family/f01-family-feed', '?genealogyId=1001', '.feed-state--list')
|
||||
await open(send, '/pages/family/f02-publish-feed', '?genealogyId=1001', '.publish-state--form')
|
||||
await open(send, '/pages/notification/n01-message-center', '', '.notice-state--list')
|
||||
await open(send, '/pages/profile/m01-profile-home', '', '.profile-state--ready')
|
||||
|
||||
// 步骤二:N01 单条消息要先标记已读再进入详情,返回后必须保留刚才的已读状态。
|
||||
await open(send, '/pages/notification/n01-message-center', '?genealogyId=1001', '.notice-state--list')
|
||||
if ((await valueOf(send, "document.querySelectorAll('.notice-card__status.is-unread').length")) !== 1) {
|
||||
throw new Error('N01 initial unread count is invalid')
|
||||
}
|
||||
await valueOf(send, "document.querySelector('.notice-card').click()")
|
||||
await waitFor(send, "location.hash.includes('/pages/notification/n02-message-detail?id=review-1&genealogyId=1001')", 'N01 first notice did not open its N02 detail')
|
||||
await waitFor(send, "Boolean(document.querySelector('.notice-state--ready'))", 'N02 detail did not render after opening the notice')
|
||||
await valueOf(send, "document.querySelector('.header-back').click()")
|
||||
await waitFor(send, "Boolean(document.querySelector('.notice-state--list'))", 'N01 did not return from N02')
|
||||
await waitFor(send, "document.querySelectorAll('.notice-card__status.is-unread').length === 0", 'N01 did not preserve the first notice read state')
|
||||
|
||||
// 步骤三:全标已读必须清除全部未读标记、隐藏页头操作,并显示项目内反馈。
|
||||
await open(send, '/pages/notification/n01-message-center', '?genealogyId=1001', '.notice-state--list')
|
||||
await valueOf(send, "document.querySelector('.header-action').click()")
|
||||
await waitFor(send, "document.querySelectorAll('.notice-card__status.is-unread').length === 0", 'N01 mark-all did not clear unread notices')
|
||||
await waitFor(send, "document.querySelector('.header-action')?.disabled === true && !document.querySelector('.header-action')?.textContent.trim()", 'N01 mark-all did not disable the completed header action')
|
||||
await waitFor(send, "document.querySelector('.app-toast')?.textContent.includes('已全部标记为已读')", 'N01 mark-all did not show the project Toast')
|
||||
|
||||
// 步骤四:保留原有空态、成功态和错误态入口,防止新增交互覆盖挤掉页面状态冒烟。
|
||||
await open(send, '/pages/family/f01-family-feed', '?state=empty&genealogyId=1001', '.feed-state--empty')
|
||||
await open(send, '/pages/family/f02-publish-feed', '?state=success&genealogyId=1001', '.publish-state--success')
|
||||
await open(send, '/pages/notification/n01-message-center', '?state=empty', '.notice-state--empty')
|
||||
await open(send, '/pages/profile/m01-profile-home', '?state=error', '.profile-state--error')
|
||||
|
||||
process.stdout.write('ROOT-PAGES-RUNTIME-SMOKE PASS\n')
|
||||
} finally {
|
||||
socket.close()
|
||||
}
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
process.stderr.write(`${error.stack || error.message}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user