const { chromium } = require('playwright');
|
const fs = require('node:fs'), path = require('node:path'), assert = require('node:assert/strict');
|
const base = process.env.MOBILE_TEST_URL || 'http://127.0.0.1:5173';
|
const out = path.resolve('.export_tmp/code-toolbar'); fs.mkdirSync(out, { recursive: true });
|
(async () => {
|
const browser = await chromium.launch({ headless: true, channel: 'msedge' });
|
try {
|
const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
|
const page = await context.newPage(), errors = [], calls = [];
|
page.on('pageerror', error => errors.push(error.message));
|
const permissions = ['bag-code','pallet','batch'].flatMap(kind => ['query','create','update','replace','delete','export'].map(action => `mes:pro-${kind}:${action}`));
|
await context.route('**/*', async route => {
|
const url = new URL(route.request().url()), p = url.pathname;
|
if (url.origin !== base) return route.abort();
|
if (!p.startsWith('/admin-api/')) return route.continue();
|
calls.push(p);
|
let data = null;
|
if (p.endsWith('/auth/login')) data = { accessToken:'fixture-token', refreshToken:'fixture-refresh', userId:7, expiresTime:Date.now()+3600000 };
|
else if (p.endsWith('/get-permission-info')) data = { user:{ id:7, nickname:'测试员', username:'fixture' }, roles:['worker'], permissions,
|
menus:[{ id:1, parentId:0, name:'一袋一码管理', path:'/bagcode', component:'Layout', visible:true, children:
|
[['bag-code','bagCode','赋码管理'],['pallet','pallet','托盘码管理'],['batch','batch','批次生产管理']].map(([key,folder,name],i)=>({id:i+2,parentId:1,path:key,name,component:`mes/pro/${folder}/index`,visible:true})) }] };
|
else if (p.endsWith('/bag-code/page')) data = { list:[{id:11,code:'6028472024079516',businessCode:'8888888888888888',itemName:'玉米种子',status:10}], total:1 };
|
else if (p.endsWith('/pallet/page')) data = { list:[{id:12,code:'P-TEST',businessCode:'7777777777777777',bagCount:1,status:10}], total:1 };
|
else if (p.endsWith('/batch/page')) data = { list:[{id:20,code:'B-TEST',businessCode:'6666666666666666',status:20}], total:1 };
|
else if (p.endsWith('/pallet/unbound-list')) data = [
|
{id:1,tempCode:'P-ONE',itemId:1,itemName:'塔河4号',itemCode:'ITEM-1',bagCount:25},
|
{id:2,tempCode:'P-TWO',itemId:1,itemName:'塔河4号',itemCode:'ITEM-1',bagCount:25},
|
{id:3,tempCode:'P-OTHER',itemId:2,itemName:'其他品种',itemCode:'ITEM-2',bagCount:25},
|
{id:4,tempCode:'P-EMPTY',bagCount:0},
|
];
|
else if (p.includes('export')) return route.fulfill({contentType:'application/zip',body:'fixture',headers:{'content-disposition':'attachment;filename=fixture.zip'}});
|
else if (p.endsWith('/generate-business-code')) data = 1;
|
else if (p.endsWith('/page')) data = {list:[],total:0};
|
else if (p.endsWith('/simple-list') || p.endsWith('/list-all-simple') || p.endsWith('/get-unread-count')) data = [];
|
return route.fulfill({json:{code:0,msg:'',data}});
|
});
|
await page.goto(base+'/auth/login');
|
await page.locator('input[autocomplete=username]').fill('fixture');
|
await page.locator('input[autocomplete=current-password]').fill('fixture-password');
|
await page.getByRole('button',{name:'登录 PC 端',exact:true}).click();
|
await page.waitForURL(url => !url.pathname.startsWith('/auth/'));
|
for (const [key,title,code] of [['bag-code','袋码列表(一袋一码)','8888888888888888'],['pallet','托盘码列表','7777777777777777'],['batch','生产批次列表','6666666666666666']]) {
|
await page.goto(base+'/bagcode/'+key);
|
await page.getByText(title,{exact:true}).waitFor();
|
await page.getByText(code,{exact:true}).first().waitFor();
|
const toolbar = page.locator('.mes-code-toolbar');
|
for (const width of [1920,1280]) {
|
await page.setViewportSize({width,height:1080});
|
const buttons = await toolbar.locator('button').evaluateAll(nodes => nodes.map(node => ({text:node.textContent.trim(),y:node.getBoundingClientRect().top,x:node.getBoundingClientRect().right})));
|
assert(buttons.length <= 6, 'Too many visible toolbar operations');
|
assert(Math.max(...buttons.map(b=>b.y))-Math.min(...buttons.map(b=>b.y)) < 4, JSON.stringify(buttons));
|
assert(buttons.every(b=>b.x <= width), 'Toolbar exceeds screen');
|
const heading = await page.getByText(title,{exact:true}).boundingBox();
|
assert(heading.height < 30, 'Title wraps');
|
await page.screenshot({path:path.join(out,`${key}-${width}.png`),fullPage:true});
|
}
|
await toolbar.getByRole('button',{name:'导出',exact:true}).click();
|
await page.getByRole('menuitem',{name:key==='bag-code'?'业务二维码':key==='pallet'?'业务二维码(选中记录)':'Excel 数据',exact:true}).waitFor();
|
await page.getByText(title,{exact:true}).click();
|
const qr = page.getByRole('button',{name:'业务二维码',exact:true});
|
if (key !== 'batch') {
|
await qr.click();
|
await page.getByRole('dialog',{name:'业务码二维码'}).waitFor();
|
assert(await page.getByRole('dialog').getByText(code,{exact:true}).isVisible());
|
await page.screenshot({path:path.join(out,`${key}-business-qr.png`)});
|
await page.keyboard.press('Escape');
|
}
|
}
|
await page.getByRole('button',{name:'新增批次',exact:true}).click();
|
const dialog=page.getByRole('dialog');await dialog.waitFor();
|
const select=dialog.locator('.ant-select').last();
|
await select.click();
|
const first=page.locator('.ant-select-item-option').filter({hasText:'P-ONE'});
|
await first.click();
|
const itemFields=dialog.getByPlaceholder('选择托盘后自动带入');
|
await page.waitForFunction(()=>[...document.querySelectorAll('input')].some(input=>input.value==='塔河4号'));
|
assert.equal(await itemFields.nth(0).inputValue(),'塔河4号');
|
assert.equal(await itemFields.nth(1).inputValue(),'ITEM-1');
|
const other=page.locator('.ant-select-item-option').filter({hasText:'P-OTHER'});
|
assert((await other.getAttribute('class')).includes('ant-select-item-option-disabled'));
|
const empty=page.locator('.ant-select-item-option').filter({hasText:'P-EMPTY'});
|
assert((await empty.getAttribute('class')).includes('ant-select-item-option-disabled'));
|
await page.locator('.ant-select-item-option').filter({hasText:'P-TWO'}).click();
|
await dialog.click({position:{x:10,y:10}});
|
await page.screenshot({path:path.join(out,'batch-variety-binding.png'),fullPage:true});
|
await page.keyboard.press('Escape');
|
if(await dialog.isVisible()) await dialog.getByRole('button',{name:/取\s*消/}).click();
|
assert.deepEqual(errors,[]);
|
console.log('PASS: three code pages, grouped toolbar at 1920/1280, export dropdown, business QR preview');
|
} finally { await browser.close(); }
|
})().catch(error=>{console.error(error);process.exitCode=1;});
|