| ¶Ô±ÈÐÂÎļþ |
| | |
| | | const { chromium } = require('playwright'); |
| | | const fs = require('fs'), path = require('path'), assert = require('assert/strict'); |
| | | const base = process.env.PC_TEST_URL || 'http://127.0.0.1:5667'; |
| | | const out = path.resolve('.export_tmp/pc-seed-quality'); fs.mkdirSync(out, { recursive: true }); |
| | | (async () => { |
| | | const browser = await chromium.launch({ headless: true, channel: 'msedge' }); |
| | | const context = await browser.newContext({ viewport: { width: 1512, height: 1100 } }); |
| | | const page = await context.newPage(), writes = [], errors = []; |
| | | page.on('pageerror', e => errors.push(e.message)); |
| | | // ä¸ç§ç±»åçå¾
æ£è¢æ¸
åï¼è¢ç 1 è¢ãæç 2 è¢ãæ¹æ¬¡ 3 è¢ |
| | | const pending = { BAG: [11], PALLET: [21, 22], BATCH: [31, 32, 33] }; |
| | | const codeOf = { BAG: 'BAG-TRACE-1', PALLET: 'PALLET-100', BATCH: 'BATCH-100' }; |
| | | let resolveMode = 'ok'; // ok | canceled | notInbound | inspected |
| | | await context.route('**/*', async route => { |
| | | const req = route.request(), u = new URL(req.url()), p = u.pathname; |
| | | if (u.origin !== base) return route.abort(); |
| | | if (!p.startsWith('/admin-api/')) return route.continue(); |
| | | let data = null; |
| | | if (p.endsWith('/auth/login')) data = { accessToken: 'test-token', refreshToken: 'test-refresh', userId: 7, expiresTime: Date.now() + 3600000 }; |
| | | else if (p.endsWith('/get-permission-info')) data = { |
| | | user: { id: 7, nickname: 'è´¨æ£å', username: 'fixture', homePath: '/mes/qc/seedQuality' }, |
| | | roles: ['worker'], permissions: ['mes:qc-seed-quality:submit', 'mes:qc-seed-quality:query'], |
| | | menus: [{ id: 1, name: 'ç§åè´¨æ£', path: '/mes/qc/seedQuality', component: 'mes/qc/seedQuality/index', visible: true }], |
| | | }; |
| | | else if (p.endsWith('/warehouse/simple-list')) data = [ |
| | | { id: 8, code: 'WK-01', name: 'ç§ååæ ¼åº', type: 20 }, |
| | | { id: 9, code: 'WK-02', name: 'å»ç»åæ ¼åº', type: 20, frozen: true }, |
| | | { id: 10, code: 'WK-03', name: 'æååº', type: 10 }, |
| | | ]; |
| | | else if (p.endsWith('/seed-quality/resolve')) { |
| | | const t = u.searchParams.get('scanType') || 'BAG'; |
| | | const shell = { scanType: t, code: codeOf[t], businessCode: '8888888888888888', batchCode: 'BATCH-1' }; |
| | | if (resolveMode === 'canceled') data = { ...shell, canceled: true, inbound: true, totalCount: 0, pendingBagIds: [], completedBagIds: [] }; |
| | | else if (resolveMode === 'notInbound') data = { ...shell, canceled: false, inbound: false, totalCount: 2, pendingBagIds: [11], completedBagIds: [] }; |
| | | else if (resolveMode === 'inspected') data = { ...shell, canceled: false, inbound: true, totalCount: 2, pendingBagIds: [], completedBagIds: [11] }; |
| | | else data = { ...shell, canceled: false, inbound: true, totalCount: pending[t].length + 1, pendingBagIds: pending[t], completedBagIds: [99] }; |
| | | } else if (p.endsWith('/seed-quality/submit-group')) { |
| | | const body = req.postDataJSON(); writes.push(body); data = { processedCount: body.bagIds.length }; |
| | | } else if (p.endsWith('/get-unread-count')) data = 0; |
| | | else if (p.endsWith('/simple-list')) data = []; |
| | | else if (p.endsWith('/page')) data = { list: [], total: 0 }; |
| | | return route.fulfill({ json: { code: 0, data, msg: '' } }); |
| | | }); |
| | | // 䏿é项åªåå½åå¯è§çé£ä¸ä¸ªï¼Ant 伿已æå¼è¿ç䏿çå¨ DOM é |
| | | const visibleOption = (label) => page.locator('.ant-select-dropdown:not(.ant-select-dropdown-hidden) .ant-select-item-option').filter({ hasText: label }); |
| | | async function pickOption(label) { await visibleOption(label).first().click(); } |
| | | async function identify(type, label) { |
| | | await page.locator('.scan-type').click(); await pickOption(label); |
| | | await page.locator('.scan-input input').fill(codeOf[type]); |
| | | // Ant å¨ä¸¤å䏿æé®ä¸æå
¥ç©ºæ ¼ï¼å¯è®¿é®åæ¯ãè¯ å«ãï¼æ
ç¨ class å®ä½ |
| | | await page.locator('.scan-input .ant-input-search-button').click(); |
| | | // æè¦å¡ä¸æ£éªå¯¹è±¡é¢æ¿é½æãæ¬æ¬¡å¾
æ£ãåæ ·ï¼æ
ç´æ¥ç颿¿éçè¢æ°æ¸²æ |
| | | await page.locator('.target-stats .highlight strong').waitFor(); |
| | | } |
| | | try { |
| | | await page.goto(base + '/auth/login'); |
| | | await page.getByRole('radio', { name: 'PC 端', exact: true }).check(); |
| | | await page.locator('input[autocomplete=username]').fill('fixture'); |
| | | await page.locator('input[autocomplete=current-password]').fill('fixture'); |
| | | await page.getByRole('button', { name: 'ç»å½ PC 端', exact: true }).click(); |
| | | await page.waitForURL('**/mes/qc/seedQuality'); |
| | | await page.locator('#__app-loading__').waitFor({ state: 'detached' }); |
| | | await page.getByRole('heading', { name: 'ç§åè´¨æ£' }).waitFor(); |
| | | // 1) æ«ç ç±»å䏿å¿
é¡»æ¯ è¢ç / æçç / æ¹æ¬¡ç ä¸é¡¹ |
| | | await page.locator('.scan-type').click(); |
| | | for (const label of ['è¢ç ', 'æçç ', 'æ¹æ¬¡ç ']) { |
| | | assert.equal(await visibleOption(label).count() > 0, true, 'ä¸æç¼ºå°é项ï¼' + label); |
| | | } |
| | | assert.equal(await page.locator('.ant-select-dropdown:not(.ant-select-dropdown-hidden) .ant-select-item-option').count(), 3, 'æ«ç ç±»åä¸æåºæ°å¥½ä¸é¡¹'); |
| | | await page.screenshot({ path: path.join(out, 'scan-type-options.png'), fullPage: true }); |
| | | await page.keyboard.press('Escape'); |
| | | // 2) 忢æ«ç ç±»åå¿
é¡»æ¸
空已è¯å«å¯¹è±¡ï¼é¿å
æ¿ä¸ä¸ä¸ªç±»åçç å¼/æ¸
åæäº¤ |
| | | await identify('BAG', 'è¢ç '); |
| | | await page.locator('.scan-type').click(); await pickOption('æçç '); |
| | | await page.waitForFunction(() => document.querySelector('.target-panel') === null); |
| | | // 3) ä¸ç§ç±»åéä¸è¯å«å¹¶æäº¤ |
| | | for (const [type, label] of [['BAG', 'è¢ç '], ['PALLET', 'æçç '], ['BATCH', 'æ¹æ¬¡ç ']]) { |
| | | await identify(type, label); |
| | | const shownPending = (await page.locator('.target-stats .highlight strong').innerText()).trim(); |
| | | assert.equal(shownPending, pending[type].length + ' è¢', type + ' æ¬æ¬¡å¾
æ£è¢æ°ä¸ç¬¦ï¼é¡µé¢æ¾ç¤ºï¼' + shownPending); |
| | | const shownCompleted = (await page.locator('.target-stats div').nth(1).locator('strong').innerText()).trim(); |
| | | assert.equal(shownCompleted, '1', type + ' å·²æ£è¢æ°ä¸ç¬¦ï¼é¡µé¢æ¾ç¤ºï¼' + shownCompleted); |
| | | assert.equal((await page.locator('.target-head .target-code').innerText()).trim(), codeOf[type], type + ' è¯å«å¯¹è±¡ç å¼ä¸ç¬¦'); |
| | | for (const field of await page.getByPlaceholder('宿µå¼').all()) await field.fill('90'); |
| | | await page.locator('.base-grid .ant-select').click(); |
| | | assert.equal(await visibleOption('å»ç»åæ ¼åº').count(), 0, 'å»ç»ä»åºä¸åºåºç°å¨åæ ¼åºä¸æä¸'); |
| | | await pickOption('ç§ååæ ¼åº'); |
| | | await page.screenshot({ path: path.join(out, 'filled-' + type.toLowerCase() + '.png'), fullPage: true }); |
| | | await page.getByRole('button', { name: 'æäº¤è´¨æ£' }).click(); |
| | | await page.getByRole('button', { name: '确认æäº¤' }).click(); |
| | | // æç¤ºæ¡ä¼å çï¼ææ¬æ¬¡è¢æ°å®ä½ï¼é¿å
å¹é
å°ä¸ä¸æ¬¡çæç¤º |
| | | await page.locator('.ant-message-notice-content').filter({ hasText: 'æ¬æ¬¡ ' + pending[type].length + ' è¢å·²æäº¤ï¼è´¨æ£åæ ¼ï¼å·²è½¬å
¥æéåæ ¼åº' }).last().waitFor(); |
| | | const w = writes.at(-1); |
| | | assert.equal(w.scanType, type, type + ' æäº¤ç scanType 䏿£ç¡®'); |
| | | assert.deepEqual(w.bagIds, pending[type], type + ' æäº¤ç bagIds ä¸è¯å«æ¸
åä¸ä¸è´'); |
| | | assert.equal(w.qualifiedWarehouseId, 8, type + ' æªå¸¦å
¥éä¸çåæ ¼åº'); |
| | | assert.equal(w.indicators.length, 4, type + ' åé¡¹ææ æªå®æ´æäº¤'); |
| | | assert.equal(w.code, codeOf[type], type + ' æäº¤çç å¼ä¸æ£ç¡®'); |
| | | await page.waitForFunction(() => document.querySelector('.target-panel') === null); |
| | | } |
| | | // 4) å·²ä½åº / æªå
¨é¨å
¥åº / æ å¾
æ£è¢ç æ¶å¿
é¡»æ¦ä½ï¼ä¸ä¸äº§çä»»ä½æäº¤ |
| | | const before = writes.length; |
| | | for (const [mode, expected] of [ |
| | | ['canceled', '该质æ£å¯¹è±¡å·²ä½åºï¼ä¸è½è´¨æ£'], |
| | | ['notInbound', 'è¯¥å¯¹è±¡çææè¢ç å°æªå
¨é¨å
¥åºï¼æä¸è½è´¨æ£'], |
| | | ['inspected', '该对象没æå¾
è´¨æ£è¢ç ï¼è¯·å¨è´¨æ£è®°å½ä¸æ¥çå·²æç»æ'], |
| | | ]) { |
| | | resolveMode = mode; |
| | | await page.locator('.scan-input input').fill(codeOf.BAG); |
| | | await page.locator('.scan-input .ant-input-search-button').click(); |
| | | await page.locator('.ant-message-notice-content').filter({ hasText: expected }).last().waitFor(); |
| | | await page.waitForFunction(() => document.querySelector('.target-panel') === null); |
| | | assert.equal(await page.getByRole('button', { name: 'æäº¤è´¨æ£' }).isDisabled(), true, mode + ' æ¶æäº¤æé®åºä¿æä¸å¯ç¨'); |
| | | } |
| | | assert.equal(writes.length, before, '被æ¦ä½çè¯å«ä¸åºäº§çæäº¤'); |
| | | assert.deepEqual(errors, []); |
| | | console.log('PASS: ç§åè´¨æ£ è¢ç /æçç /æ¹æ¬¡ç ä¸ç±»å䏿ãè¯å«èå´æ ¸å¯¹ãåç»æäº¤ãåæ ¼åºè¿æ»¤ä¸å¼å¸¸æ¦æª'); |
| | | } catch (e) { |
| | | await page.screenshot({ path: path.join(out, 'failure.png'), fullPage: true }); |
| | | console.error(e); process.exitCode = 1; |
| | | } finally { await browser.close(); } |
| | | })(); |