80 lines
9.8 KiB
JavaScript
80 lines
9.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
import { pathToFileURL } from 'node:url';
|
|
const module = await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE ?? '/home/mes006/.npm/_npx/e41f203b7505f1fb/node_modules/playwright/index.js'));
|
|
const browser = await (module.default ?? module).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 output = new URL('../coverage/glb-machine-manager/workbench/', import.meta.url); await mkdir(output, { recursive: true });
|
|
const report = { report_id: 'GLB-MGR-E14', 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 expectValue = async (locator, value) => { await locator.evaluate((el, expected) => new Promise((resolve, reject) => { const end = Date.now() + 5000; const check = () => Number(el.value) === expected ? resolve(true) : Date.now() > end ? reject(new Error(`value ${el.value} != ${expected}`)) : setTimeout(check, 20); check(); }), value); };
|
|
const c = (id) => page.locator(`[data-axis-control="${id}"]`);
|
|
const preview = page.locator('[data-machine-manager-preview]');
|
|
const choose = async (name) => { await c('machine-manager-tab-structure').click(); await c('machine-tree-search').fill(name); const n = c('machine-tree-node').filter({ has: page.locator('span').filter({ hasText: new RegExp(`^${name}$`) }) }).first(); await n.click(); };
|
|
try {
|
|
await page.goto(report.url); await page.waitForFunction(() => document.querySelector('main.axis-app')?.dataset.axisProgramLoading === 'false' && document.querySelector('main.axis-app')?.dataset.axisStateSource === 'linuxcnc-wasm');
|
|
await c('machine-manager-settings').click(); assert.equal(await page.locator('.machine-preview-empty').isVisible(), true);
|
|
const fileDialog = page.locator('.machine-manager-dialog'); const chooser = page.waitForEvent('filechooser'); await c('machine-manager-import').click(); await chooser; await fileDialog.dispatchEvent('cancel'); assert.equal(await fileDialog.isVisible(), true); await page.evaluate(() => window.dispatchEvent(new Event('focus'))); await page.waitForTimeout(20); report.checks.push('Open Files Cancel leaves the machine manager dialog open');
|
|
const bytes = await readFile(new URL('../MILL700-U_1.glb', import.meta.url));
|
|
const upload = { name: 'MILL700-U_1.glb', mimeType: 'model/gltf-binary', buffer: bytes };
|
|
await c('machine-manager-files').setInputFiles(upload); await page.waitForFunction(() => document.querySelectorAll('[data-axis-control="machine-tree-node"]').length >= 132);
|
|
await choose('MILL700-A-主轴-JT3'); await c('machine-tree-axis-role').selectOption('Z');
|
|
await c('machine-manager-undo').click(); assert.equal(await c('machine-tree-axis-role').inputValue(), '');
|
|
await c('machine-manager-redo').click(); assert.equal(await c('machine-tree-axis-role').inputValue(), 'Z');
|
|
await c('machine-axis-locate-z').click(); assert.equal(await c('machine-tree-search').inputValue(), ''); assert.match(await page.locator('.machine-part-editor h3').textContent(), /主轴-JT3/);
|
|
assert.equal(await c('machine-tree-node').filter({ hasText:'MILL700-A-主轴-JT3' }).first().isVisible(), true);
|
|
report.checks.push('search expands real nested nodes; axis overview locates selection; binding undo/redo');
|
|
await c('machine-joint-value').fill('12.5'); const local = JSON.parse(await preview.getAttribute('data-machine-manager-selected-transform')).local;
|
|
await c('machine-joint-value').fill(''); assert.equal(await c('machine-joint-value').getAttribute('aria-invalid'), 'true'); assert.match(await c('machine-manager-validation').textContent(), /修正/);
|
|
assert.deepEqual(JSON.parse(await preview.getAttribute('data-machine-manager-selected-transform')).local, local);
|
|
await c('machine-joint-value').fill('0'); assert.equal(await c('machine-joint-value').getAttribute('aria-invalid'), 'false');
|
|
for (let i=0; i<4; i++) {
|
|
await choose('MILL700-A-主轴-JT2'); await choose('MILL700-A-主轴-JT3');
|
|
await c('machine-joint-value').fill('30'); await expectValue(c('machine-joint-value'),30);
|
|
const v=JSON.parse(await preview.getAttribute('data-machine-manager-selected-transform')).local;
|
|
assert.ok(Math.abs(v[2] - .3989253330230713)<1e-7, 'switching selection and repeated fill must not concatenate input');
|
|
}
|
|
await c('machine-joint-step-plus').click(); await expectValue(c('machine-joint-value'),31);
|
|
await c('machine-joint-step-minus').click(); await expectValue(c('machine-joint-value'),30);
|
|
await c('machine-joint-reset').click(); await expectValue(c('machine-joint-value'),0);
|
|
report.checks.push('empty input preserves last pose; repeated selection/input does not concatenate; single-axis step and reset');
|
|
for (const [axis, name] of [['X','MILL700-A-主轴-JT1'],['Y','MILL700-A-主轴-JT2'],['A','MILL700-A-工作台-JT1'],['C','MILL700-A-工作台-JT2']]) { await choose(name); await c('machine-tree-axis-role').selectOption(axis); }
|
|
assert.match(await c('machine-manager-validation').textContent(), /检查通过/); assert.equal(await c('machine-manager-apply').isEnabled(), true);
|
|
await c('machine-manager-tab-calibration').click(); const off = page.locator('fieldset.machine-vector').filter({ hasText:'A 到 C 轴偏置' });
|
|
await off.getByLabel('X', { exact:true }).fill('5'); assert.match(await c('machine-manager-validation').textContent(), /必须为 0/); assert.equal(await c('machine-manager-export').isDisabled(), true);
|
|
await c('machine-manager-undo').click(); await expectValue(off.getByLabel('X', { exact:true }), 0);
|
|
await off.getByLabel('Y', { exact:true }).fill('18'); await c('machine-manager-undo').click(); await expectValue(off.getByLabel('Y', { exact:true }), 0); await c('machine-manager-redo').click(); await expectValue(off.getByLabel('Y', { exact:true }), 18);
|
|
report.checks.push('TRT forbidden offset blocks export before build; calibration undo/redo');
|
|
await c('machine-manager-tab-structure').click(); await c('machine-axis-locate-z').click();
|
|
for (const action of ['fit','selected','front','top']) { await c(`machine-view-${action}`).click(); assert.equal(await preview.getAttribute('data-machine-manager-view'),action); }
|
|
await c('machine-view-fit').click(); await c('machine-manager-show-origin').uncheck(); await c('machine-manager-show-origin').check();
|
|
await c('machine-manager-delete').click(); await page.waitForFunction(() => document.querySelector('[data-machine-manager-preview]')?.dataset.machineManagerPartCount === '0');
|
|
await c('machine-manager-undo').click(); await page.waitForFunction(() => document.querySelector('[data-machine-manager-preview]')?.dataset.machineManagerPartCount === '1');
|
|
assert.equal(await c('machine-manager-apply').isEnabled(), true); await c('machine-axis-locate-z').click(); assert.equal(await c('machine-tree-axis-role').inputValue(), 'Z');
|
|
report.checks.push('view presets and selected fitting; deletion undo restores model with all axis bindings');
|
|
const validationBefore = await c('machine-manager-validation').textContent();
|
|
await c('machine-manager-files').setInputFiles([upload,{ name:'bad.glb',mimeType:'model/gltf-binary',buffer:Buffer.from('bad') }]);
|
|
await page.waitForFunction(() => document.querySelector('.machine-manager-workbench')?.getAttribute('aria-busy') === 'false');
|
|
assert.equal(await preview.getAttribute('data-machine-manager-part-count'),'1'); assert.equal(await c('machine-manager-validation').textContent(),validationBefore);
|
|
report.checks.push('failed batch import leaves existing assembly intact');
|
|
await c('machine-manager-tab-motion').click(); await c('machine-joint-follow-live').check(); assert.equal(await c('machine-manager-undo').isDisabled(),true);
|
|
await c('machine-manager-tab-structure').click(); assert.equal(await c('machine-tree-axis-role').isDisabled(),true); assert.equal(await c('machine-manager-delete').isDisabled(),true);
|
|
await c('machine-manager-tab-motion').click(); await c('machine-joint-follow-live').uncheck();
|
|
await c('machine-manager-tab-structure').click(); await c('machine-view-fit').click();
|
|
await page.screenshot({ path:new URL('desktop.png',output).pathname });
|
|
for (const [width,height] of [[1154,520],[720,900]]) {
|
|
await page.setViewportSize({width,height}); await page.waitForTimeout(300);
|
|
const bounds = await page.locator('.machine-manager-dialog').boundingBox(); assert.ok(bounds.x >= 0 && bounds.y >= 0 && bounds.x+bounds.width <= width+1 && bounds.y+bounds.height <=height+1);
|
|
const footer = await page.locator('.machine-manager-footer').boundingBox(); assert.ok(footer.y+footer.height <=height);
|
|
const buffer = (await preview.getAttribute('data-machine-manager-buffer-size')).split('x').map(Number); assert.ok(buffer.every((n)=>n>0 && n<=4096));
|
|
assert.equal(await page.locator('.machine-manager-dialog').evaluate((el)=>el.scrollWidth<=el.clientWidth+1),true);
|
|
await page.screenshot({ path:new URL(`viewport-${width}.png`,output).pathname });
|
|
}
|
|
report.checks.push('live mode locks edits; desktop, short viewport and narrow viewport keep footer visible without overflow');
|
|
await page.setViewportSize({width:1440,height:900});
|
|
await page.keyboard.press('Escape'); await c('machine-manager-settings').click(); await c('machine-axis-locate-z').click(); assert.equal(await c('machine-tree-axis-role').inputValue(),'Z');
|
|
assert.deepEqual(report.errors, []); report.status='verified';
|
|
} catch(e) { report.status='failed'; report.error=e.stack; await page.screenshot({path:new URL('failure.png',output).pathname}).catch(()=>{}); throw e; }
|
|
finally { await writeFile(new URL('browser.report.json',output),JSON.stringify(report,null,2)+'\n'); await browser.close(); }
|
|
console.log(JSON.stringify(report));
|