// Local YCode fixture behavior/rendering QA. Does not inspect WorkBuddy. if (!process.versions.electron) { const env={...process.env}; delete env.ELECTRON_RUN_AS_NODE const result=require('node:child_process').spawnSync(require('electron'),[__filename],{env,windowsHide:true,stdio:'inherit',timeout:60000}) process.exit(result.status??1) } const {app,BrowserWindow}=require('electron') const fs=require('node:fs/promises'),path=require('node:path'),assert=require('node:assert/strict') app.setPath('userData',path.resolve('.tmp/preview-qa-user-data')) app.disableHardwareAcceleration() let win const errors=[] const read=code=>win.webContents.executeJavaScript(code) async function waitFor(code){for(let n=0;n<120;n++){if(await read(code))return;await new Promise(r=>setTimeout(r,40))}throw new Error('Condition failed: '+code)} async function clickText(selector,text){await read(`Array.from(document.querySelectorAll(${JSON.stringify(selector)})).find(n=>n.textContent===${JSON.stringify(text)}).click()`)} async function settled(){await read('document.fonts.ready.then(()=>Promise.all(document.getAnimations().filter(a=>Number.isFinite(a.effect.getTiming().iterations)).map(a=>a.finished.catch(()=>{})))).then(()=>new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))))')} async function shot(name){await settled();await new Promise(r=>{win.webContents.once('paint',r);win.webContents.invalidate()});await fs.writeFile(path.resolve('.tmp/'+name),(await win.webContents.capturePage()).toPNG())} app.whenReady().then(async()=>{ win=new BrowserWindow({show:false,useContentSize:true,width:1336,height:901,webPreferences:{offscreen:true,contextIsolation:true}}) win.webContents.on('console-message',(_event,level,message)=>{if(level===3)errors.push(message)}) await win.loadURL('http://127.0.0.1:8789/?fixture=artifact-source') await waitFor("document.querySelectorAll('.msg__artifact').length>=5") await clickText('.msg__artifact','异步 Markdown') await waitFor("document.querySelector('.markdown-viewer')?.textContent.includes('异步加载成功')") assert.equal(await read('document.documentElement.dataset.fixtureReadText'),'notes/readme.md') await clickText('.msg__artifact','慢速 Markdown') await clickText('.msg__artifact','缓存 Markdown') await waitFor("document.querySelector('.markdown-viewer')?.textContent.includes('缓存内容')") await new Promise(r=>setTimeout(r,350)) assert.ok(await read("!document.querySelector('.markdown-viewer').textContent.includes('过期读取')")) await clickText('.msg__artifact','HTML 预览') await waitFor("document.querySelector('.artifact-html-frame')?.srcdoc.includes('HTML 预览成功')") const html=await read(`(()=>{const e=document.querySelector('.artifact-html-frame'),h=document.querySelector('.artifact-media-preview__header');return{sandbox:e.getAttribute('sandbox'),height:h.getBoundingClientRect().height,frameWidth:e.getBoundingClientRect().width,frameHeight:e.getBoundingClientRect().height,padding:getComputedStyle(document.querySelector('.resource-preview__body')).padding}})()`) assert.equal(html.height,48) assert.equal(html.padding,'0px') assert.ok(html.frameWidth>300) assert.ok(html.frameHeight>300) assert.ok(html.sandbox.includes('allow-scripts')) assert.ok(!html.sandbox.includes('allow-same-origin')) const frame = win.webContents.mainFrame.framesInSubtree.find(frame=>frame!==win.webContents.mainFrame) assert.ok(frame,'HTML preview must have a child frame') for(let n=0;n<80;n++){if(await frame.executeJavaScript("document.body?.textContent.includes('HTML 预览成功')"))break;await new Promise(r=>setTimeout(r,40))} html.renderedText=await frame.executeJavaScript('document.body.textContent') assert.match(html.renderedText,/HTML 预览成功/) await read("document.querySelector('.artifact-media-preview__button').click()") await waitFor("!!document.documentElement.dataset.fixtureDownload") assert.equal(JSON.parse(await read('document.documentElement.dataset.fixtureDownload')).filename,'preview.html') await shot('conversation-artifact-html-2026-10-15.png') await clickText('.msg__artifact','读取失败') await waitFor("document.querySelector('.custom-artifact-error[role=alert]')?.textContent.includes('加载失败')") await win.loadURL('http://127.0.0.1:8789/?fixture=dialogue-media') await waitFor("document.querySelectorAll('img.cr-image-block').length===2") await read("document.querySelector('img.cr-image-block').click()") await waitFor("document.querySelector('.wb-image-preview__image')?.naturalWidth>0") await read("document.querySelector('.wb-image-preview [aria-label=放大]').click()") assert.equal(await read("document.querySelector('.wb-image-preview__scale').textContent"),'125%') await read("document.querySelector('.wb-image-preview [aria-label=向左旋转]').click()") assert.ok(await read("document.querySelector('.wb-image-preview__image-wrap').style.transform.includes('rotate(-90deg)')")) await read("document.querySelector('.wb-image-preview [aria-label=镜像]').click()") assert.ok(await read("document.querySelector('.wb-image-preview__image-wrap').style.transform.includes('scaleX(-1)')")) await read("document.querySelector('.wb-image-preview [aria-label=下一张]').click()") await waitFor("document.querySelector('.wb-image-preview__count')?.textContent==='2/2'") assert.equal(await read("document.querySelector('.wb-image-preview__scale').textContent"),'100%') await read("document.querySelector('.wb-image-preview [aria-label=下载图片]').click()") await waitFor("!!document.documentElement.dataset.fixtureImageDownload") await settled() const image=await read(`(()=>{const s=document.querySelector('.wb-image-preview__stage'),t=document.querySelector('.wb-image-preview__toolbar'),c=document.querySelector('.wb-image-preview__close-area');return{stage:{width:s.getBoundingClientRect().width,height:s.getBoundingClientRect().height},toolbarBottom:getComputedStyle(t).bottom,closeTop:getComputedStyle(c).top,closeRight:getComputedStyle(c).right,desktop:document.body.dataset.electronDesktop,platform:document.body.dataset.platform}})()`) assert.deepEqual(image.stage,{width:1256,height:701}) assert.equal(image.toolbarBottom,'40px') assert.equal(image.desktop,'true') assert.equal(image.closeTop,'40px') assert.equal(image.closeRight,'148px') await shot('conversation-image-preview-2026-10-15.png') win.webContents.sendInputEvent({type:'keyDown',keyCode:'Escape'}) win.webContents.sendInputEvent({type:'keyUp',keyCode:'Escape'}) await waitFor("!document.querySelector('.wb-image-preview')") const report={scope:'YCode offline fixtures only; original application parity unverified',html,image,markdownRead:true,staleReadIgnored:true,readErrorVisible:true,imageZoomRotateFlipGalleryDownloadEscape:true,consoleErrors:errors} assert.deepEqual(errors,[]) await fs.writeFile(path.resolve('.tmp/conversation-preview-qa.json'),JSON.stringify(report,null,2)) console.log(JSON.stringify(report)) app.quit() }).catch(error=>{console.error(error);app.exit(1)})