59 lines
6.3 KiB
JavaScript
59 lines
6.3 KiB
JavaScript
import fs from 'node:fs'
|
|
|
|
const read=file=>fs.readFileSync(file,'utf8')
|
|
const expect=(condition,message)=>{if(!condition){console.error(`FAIL: ${message}`);process.exit(1)}console.log(`PASS: ${message}`)}
|
|
|
|
const dialog=read('packages/kbx-ui/src/components/KbxDialog.vue')
|
|
const drawer=read('packages/kbx-ui/src/components/KbxDrawer.vue')
|
|
for(const [name,source] of [['Dialog',dialog],['Drawer',drawer]]){
|
|
expect(source.includes('restoreTarget')&&source.includes("@hide=\"restoreFocus\"")&&source.includes('target.isConnected'),`${name} restores focus only to a still-valid invoking control after overlay close`)
|
|
expect(source.includes("target.focus({preventScroll:true})"),`${name} restores focus without unexpected viewport jumps`)
|
|
}
|
|
expect(dialog.includes('restoreFocus?:boolean')&&dialog.includes("!props.restoreFocus"),'Dialog supports an explicit owner-managed focus lifecycle escape hatch')
|
|
const lookupDialog=read('packages/kbx-ui/src/components/KbxLookupDialog.vue')
|
|
expect(lookupDialog.includes(':restore-focus="false"'),'Lookup disables generic Dialog restore because successful selection intentionally advances to the next field')
|
|
|
|
const excel=read('packages/kbx-ui/src/components/KbxExcelImport.vue')
|
|
expect(excel.includes('watch(stage, async (current, previous)')&&excel.includes('data-kbx-stage-heading')&&excel.includes("heading?.focus({ preventScroll: true })"),'T08 transfers keyboard focus to the new six-stage work surface after DOM replacement')
|
|
expect((excel.match(/data-kbx-stage-heading/g)??[]).length>=6,'T08 gives every import stage an explicit focus landing')
|
|
|
|
const operationsApi=read('apps/web/src/modules/common/operations/operationsApi.ts')
|
|
expect(operationsApi.includes('ClaimWorkItemsResponse')&&operationsApi.includes('claimedCount')&&operationsApi.includes('skippedCount'),'T06 FE consumes the authoritative bulk claim result instead of treating HTTP 200 as all-success')
|
|
const operations=read('apps/web/src/modules/common/operations/OperationsQueuePage.vue')
|
|
expect((operations.includes('bulkReceipt')||operations.includes('actionReceipt'))&&(operations.includes('data-kbx-surface="bulk-receipt"')||operations.includes('data-kbx-surface="authoritative-action-receipt"'))&&operations.includes('담당 지정이 일부 처리되었습니다.'),'T06 renders partial bulk outcome as a persistent inline receipt')
|
|
expect(operations.includes('내 업무 보기')&&operations.includes('최신 상태 조회'),'T06 partial bulk receipt exposes concrete recovery actions')
|
|
|
|
const retryQueue=read('apps/web/src/modules/wms/picking/wmsRetryQueue.ts')
|
|
expect(retryQueue.includes("STORAGE_PREFIX = 'kbx:wms:safe-retry:v2:'")&&retryQueue.includes('scopeHash(scope')&&retryQueue.includes('scope&&scope!==ANONYMOUS_SCOPE?localStorage:sessionStorage'),'T09 safe-retry storage is tenant/user-scope partitioned and anonymous contexts remain session-only')
|
|
expect(retryQueue.includes("localStorage.removeItem(LEGACY_STORAGE_KEY)")&&retryQueue.includes('Never replay it'),'T09 retires the old unscoped shared-PDA retry queue instead of replaying it')
|
|
expect(retryQueue.includes('MAX_QUEUE_ITEMS = 32')&&retryQueue.includes('.filter(validItem)'),'T09 bounds and validates browser-persisted retry commands before replay')
|
|
const pickingVm=read('apps/web/src/modules/wms/picking/useWmsPicking.ts')
|
|
expect(pickingVm.includes('KbxScreenPreferenceScopeKey')&&pickingVm.includes('retryScope.value'),'T09 binds retry persistence to the same tenant/user UI scope used by the application shell')
|
|
|
|
const app=read('apps/web/src/App.vue')
|
|
expect(/app-version="v\d+-fe-[^"]+"/.test(app) && !app.includes('v51-fe-presentation-workbench'),'Runtime feedback/telemetry metadata carries a current versioned FE build identity instead of stale v51')
|
|
|
|
const demo=read('apps/web/src/http/demo/installFrontendDemoApi.ts')
|
|
expect(demo.includes('claimedCount')&&demo.includes('skippedCount'),'Demo API mirrors the real partial bulk claim response contract')
|
|
expect(demo.includes("targetField:'orderNo'")&&demo.includes("targetField:'warehouseCode'")&&demo.includes("targetField:'orderQty'"),'Demo T08 supplies a complete required-field mapping so browser Golden Flow can actually reach validation')
|
|
|
|
const referenceHtml=read('apps/web/fe-reference/index.html')
|
|
const referenceJs=read('apps/web/fe-reference/kbx-fe.js')
|
|
const referenceCss=read('apps/web/fe-reference/kbx-fe.css')
|
|
expect(/KBX FE Reference Lab v\d+ ·/.test(referenceHtml) && !referenceHtml.includes('KBX FE Reference Lab v51'),'Static HTML reference carries a current versioned FE build identity')
|
|
expect(referenceJs.includes('importFocusStep')&&referenceJs.includes('data-import-stage-heading')&&referenceJs.includes('target?.focus({preventScroll:true})'),'Static HTML/JavaScript T08 mirrors stage-focus continuity without stealing focus on progress polling rerenders')
|
|
expect(!referenceJs.includes("row.actual=row.expected")&&referenceJs.includes('원천 OMS/WMS 값은 이 화면에서 직접 덮어쓰지 않습니다.'),'Static T07 no longer fabricates reconciliation success by mutating reference truth client-side')
|
|
expect(referenceCss.includes('.import-stage-focus:focus-visible')&&referenceCss.includes('@media(forced-colors:active)'),'Static import stage focus remains visible in normal and forced-color themes')
|
|
|
|
const importE2e=read('tests/e2e/oms-order-import.spec.ts')
|
|
expect(importE2e.includes("Buffer.from('KBX E2E demo workbook')")&&!importE2e.includes('orders-valid-and-invalid.xlsx\'\)'), 'T08 E2E no longer depends on a missing binary workbook fixture')
|
|
expect(importE2e.includes('toBeFocused()')&&importE2e.includes("name:'반영 결과'"),'T08 E2E asserts stage-focus continuity through terminal result')
|
|
const keyboardE2e=read('tests/e2e/kbx-keyboard-regression.spec.ts')
|
|
expect(keyboardE2e.includes('lookup Escape returns focus')&&keyboardE2e.includes('await expect(customerCode).toBeFocused()'),'Keyboard regression explicitly covers Lookup Esc focus restoration')
|
|
|
|
const manifest=read('packages/kbx-ui/src/registry/componentManifest.ts')
|
|
expect(manifest.includes("name: 'KbxExcelImport'")&&manifest.includes("version: '1.3.0'"),'T08 focus lifecycle change is component-versioned')
|
|
expect(manifest.includes("name: 'KbxDialog'")&&manifest.includes("version:'1.1.0'")&&manifest.includes("name: 'KbxDrawer'")&&manifest.includes("version:'1.1.0'"),'Overlay focus lifecycle changes are component-versioned')
|
|
|
|
console.log('PASS: FE interaction closure hardening v56 contract')
|