import assert from 'node:assert/strict'; import { mkdir,readFile,writeFile } from 'node:fs/promises'; import { pathToFileURL } from 'node:url'; const imported=await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE??'/home/mes006/.npm/_npx/e41f203b7505f1fb/node_modules/playwright/index.js')); const browser=await(imported.default??imported).chromium.launch({headless:true,executablePath:'/usr/bin/google-chrome',args:['--no-sandbox','--use-angle=swiftshader','--enable-unsafe-swiftshader']}); const page=await browser.newPage({viewport:{width:1440,height:900}});const c=id=>page.locator(`[data-axis-control="${id}"]`); const out=new URL('../coverage/glb-machine-manager/program-compatibility/',import.meta.url);await mkdir(out,{recursive:true}); const report={report_id:'TRT-PROGRAM-COMPAT-BROWSER',status:'running',url:process.env.MACHINE_MANAGER_URL??'http://127.0.0.1:5180/',checks:[],errors:[]}; page.on('pageerror',e=>report.errors.push(e.message)); page.on('console',m=>{if(['error','warning'].includes(m.type()))report.errors.push(m.text());}); const idle=()=>page.waitForFunction(()=>document.querySelector('main.axis-app')?.dataset.axisProgramLoading==='false'&&document.querySelector('main.axis-app')?.dataset.axisStateSource==='linuxcnc-wasm',null,{timeout:60000}); const checkProgram=async(coordinates)=>{ const path=`boat-${coordinates.toLowerCase()}.ngc`; assert.match(await c('workspace-case-select').inputValue(),new RegExp(`${coordinates.toLowerCase()}-trt.ini`)); await page.waitForFunction(path=>document.querySelector('main.axis-app')?.dataset.axisProgramPath?.endsWith(path),path); assert.match(await page.locator('.case-status').textContent(),new RegExp(path)); const text=await c('program-editor').inputValue();assert.match(text,new RegExp(`${coordinates[3]}[-+0-9.]`,'i')); const other=coordinates[3]==='A'?'B':'A'; assert.equal(new RegExp(`\\b${other}[-+0-9.]`,'i').test(text.replace(/\([^)]*\)/g,'').replace(/;.*/g,'')),false); }; const importBc=async()=>{await c('machine-glb-settings').click();await c('machine-glb-file').setInputFiles(new URL('../coverage/glb-machine-manager/machine-type/test-xyzbc.glb',import.meta.url).pathname);await idle();await page.waitForFunction(()=>document.querySelector('[data-axis-control="workspace-case-select"]')?.value.includes('xyzbc-trt'));await page.keyboard.press('Escape');}; try{ await page.goto(report.url);await idle();await checkProgram('XYZAC'); await importBc();await checkProgram('XYZBC');report.checks.push('AC to BC model import replaces source/path/preview with BC boat program'); await c('program-file-input').setInputFiles({name:'renamed.ngc',mimeType:'text/plain',buffer:Buffer.from('G21 G90\nG1 X1 A0 C10 F120\nM2\n')});await idle();assert.match(await page.locator('.case-status').textContent(),/不匹配/);assert.match(await page.locator('main.axis-app').getAttribute('data-axis-program-path'),/boat-xyzbc.ngc$/); report.checks.push('renamed AC file rejected on BC; previous loaded taskfile remains intact'); const beforeReload=await c('program-editor').inputValue();await c('program-editor').fill('G21 G90\nG1 A10 F120\nM2\n');await c('toolbar-reload').click();await idle();assert.match(await page.locator('.preview-load-indicator').textContent(),/不匹配/);assert.match(await page.locator('main.axis-app').getAttribute('data-axis-program-path'),/boat-xyzbc.ngc$/);await c('program-editor').fill(beforeReload); report.checks.push('editor reload also rejects wrong-axis program without replacing loaded taskfile'); const generic='G21 G90\nG1 X1 Y2 F120\nM2\n';await c('program-file-input').setInputFiles({name:'generic.ngc',mimeType:'text/plain',buffer:Buffer.from(generic)});await idle(); await importBc();assert.equal(await c('program-editor').inputValue(),generic);assert.equal(await page.locator('main.axis-app').getAttribute('data-axis-program-path'),'browser/generic.ngc');report.checks.push('same-type reimport preserves custom compatible program'); await c('machine-glb-settings').click();await c('machine-glb-ac').click();await idle();await page.keyboard.press('Escape');await checkProgram('XYZAC');report.checks.push('BC to AC model import loads AC boat'); await c('program-file-input').setInputFiles({name:'wrong-b.ngc',mimeType:'text/plain',buffer:Buffer.from('G21 G90\nG1 B0 X1 F120\nM2\n')});await idle();assert.match(await page.locator('.case-status').textContent(),/不匹配/); await c('workspace-load-boat').click();await idle();await checkProgram('XYZAC'); // Saved model applied from manager must follow the same configuration transaction. await c('machine-manager-settings').click();await c('machine-manager-files').setInputFiles(new URL('../coverage/glb-machine-manager/machine-type/test-xyzbc.glb',import.meta.url).pathname);await page.waitForFunction(()=>document.querySelector('[data-axis-control="machine-manager-type"]')?.value==='XYZBC');await c('machine-manager-apply').click();await idle();await page.keyboard.press('Escape');await checkProgram('XYZBC');report.checks.push('manager apply also switches program to matching BC family'); await c('toolbar-power').click();await page.waitForFunction(()=>document.querySelector('main.axis-app')?.dataset.axisStateMachine==='ON');await c('manual-home-all').click();await page.waitForFunction(()=>document.querySelector('main.axis-app')?.dataset.axisHomed==='[true,true,true,true,true]',null,{timeout:60000});await c('toolbar-run').click();await page.waitForFunction(()=>document.querySelector('main.axis-app')?.dataset.axisProgramStatus==='running');await checkProgram('XYZBC');await page.waitForFunction(()=>Number(document.querySelector('main.axis-app')?.dataset.axisCurrentLine)>0 && JSON.parse(document.querySelector('.xyzac-machine-view')?.dataset.xyzacJoints??'[]').some(v=>Math.abs(v)>1e-6),null,{timeout:60000});await page.screenshot({path:new URL('bc-running.png',out).pathname}); report.checks.push('BC machine runs BC G-code after home; header/controller/program agree');assert.deepEqual(report.errors,[]);report.status='verified'; }catch(e){report.status='failed';report.error=e.stack;await page.screenshot({path:new URL('failure.png',out).pathname}).catch(()=>{});throw e;}finally{await writeFile(new URL('browser.report.json',out),JSON.stringify(report,null,2)+'\n');await browser.close();} console.log(JSON.stringify(report));