| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- import assert from 'node:assert/strict'
- import { readFileSync } from 'node:fs'
- import test from 'node:test'
- import { parse } from '@vue/compiler-sfc'
- import ts from 'typescript'
- import * as stopForms from '../src/utils/pl-plan-stop-form'
- import { collectStopContractIds } from '../src/utils/pl-plan-contract-product'
- const source = parse(readFileSync(new URL('../src/components/business/pl-plan-form-dialog/index.vue', import.meta.url), 'utf8')).descriptor.scriptSetup!.content
- const ast = ts.createSourceFile('plan.ts', source, ts.ScriptTarget.Latest, true)
- function contractWatcher(side: 'load' | 'delivery', bindings: Record<string, unknown>) {
- const statement = ast.statements.find((node) => {
- if (!ts.isExpressionStatement(node) || !ts.isCallExpression(node.expression)) return false
- const call = node.expression
- return call.expression.getText(ast) === 'watch' && (side === 'load'
- ? call.arguments[0].getText(ast) === '() => loadForm.value.contracts'
- : call.arguments[0].getText(ast).includes('contractKey: collectStopContractIds'))
- }) as ts.ExpressionStatement
- assert.ok(statement, 'actual contract watcher exists')
- const callback = (statement.expression as ts.CallExpression).arguments[1].getText(ast)
- return new Function(...Object.keys(bindings), ts.transpile(`let loadContractFetchSeq = 0; const run = ${callback};`) + ';return run')(...Object.values(bindings))
- }
- for (const mobile of [false, true]) {
- for (const side of ['load', 'delivery'] as const) {
- for (const change of ['add', 'remove', 'clear'] as const) {
- test(`${mobile ? 'H5' : 'desktop'} ${side} ${change} contracts keeps unaffected row identities`, async () => {
- const kept = { id: 'row-a', planProductId: 'pp-a', contractId: 'a', contractProductId: 'line-a', productId: 'sku', inboundQty: 3, archiveRemark: 'preserve', planQty: 8 }
- const removed = { id: 'row-b', planProductId: 'pp-b', contractId: 'b', productId: 'sku', planQty: 6 }
- const legacy = { id: 'row-old', planProductId: 'pp-old', productId: 'legacy', planQty: 2 }
- const before = ['a', 'b']
- const after = change === 'add' ? ['a', 'b', 'c'] : change === 'remove' ? ['a'] : []
- const stop = { id: 'stop', contracts: after.map(contractId => ({ contractId })), products: [kept, removed, legacy] }
- const loadForm = { value: stop }
- const deliveryForms = { value: [stop] }
- const run = contractWatcher(side, {
- isPageVariant: { value: mobile }, pageReady: { value: true }, pageLoadGeneration: 1,
- detailLoading: { value: false }, suppressStopProductSync: { value: false },
- loadForm, deliveryForms, collectStopContractIds, mobileStopIdentity: () => 1,
- deliveryContractFetchSeqByIndex: {}, loadContractProductIds: { value: [] },
- contractProductIdsCache: { value: {} }, fetchContractProductIds: async () => {},
- isPageLoadCurrent: () => true, unionContractProductIds: () => ['sku', 'legacy'],
- filterProductsByAllowedProductIds: (rows: unknown[]) => rows, syncFromLoadProducts: () => {},
- retainStopProductsForContracts: (stopForms as any).retainStopProductsForContracts
- })
- if (side === 'load') await run(stop.contracts, before.map(contractId => ({ contractId })))
- else await run([{ identity: mobile ? 1 : undefined, contractKey: after.join(',') }], [{ identity: mobile ? 1 : undefined, contractKey: before.join(',') }])
- const products = side === 'load' ? loadForm.value.products : deliveryForms.value[0].products
- const expected = change === 'add' ? [kept, removed, legacy] : change === 'remove' ? [kept] : []
- assert.deepEqual(products, expected)
- expected.forEach((row, index) => assert.equal(products[index], row, 'keep original row object and all saved fields'))
- })
- }
- }
- }
|