112 lines
3.9 KiB
TypeScript
112 lines
3.9 KiB
TypeScript
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 navigation from '../src/utils/mp-webview'
|
|
|
|
function handler(file: string, name: string, bindings: Record<string, any>) {
|
|
const source = parse(readFileSync(new URL(`../src/${file}`, import.meta.url), 'utf8')).descriptor
|
|
.scriptSetup!.content
|
|
const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true)
|
|
const fn = ast.statements.find(
|
|
(node) => ts.isFunctionDeclaration(node) && node.name?.text === name
|
|
)
|
|
assert.ok(fn, `${name} must exist`)
|
|
return new Function(...Object.keys(bindings), ts.transpile(fn.getText(ast)) + `;return ${name}`)(
|
|
...Object.values(bindings)
|
|
)
|
|
}
|
|
|
|
test('mobile quote validates freight, deposit and validity bounds before either save path', () => {
|
|
const form = {
|
|
value: {
|
|
quoteType: 'sales',
|
|
supplierId: 's',
|
|
customerId: 'c',
|
|
contactId: 'p',
|
|
ownerUserId: 'u',
|
|
quoteDate: '2026-10-24',
|
|
validityDays: 30,
|
|
freight: 0,
|
|
barrelDeposit: 0
|
|
} as Record<string, any>
|
|
}
|
|
const validate = handler('views/crm/quote/components/QuoteFormPanel.vue', 'pageMissingMessage', {
|
|
form,
|
|
isPageVariant: { value: true },
|
|
quoteMeta: { blockingMessage: () => '' },
|
|
basicLabels: { value: {} }
|
|
})
|
|
assert.equal(validate(), '')
|
|
for (const field of ['freight', 'barrelDeposit']) {
|
|
for (const invalid of [-1, '-0.01', 'invalid', Infinity]) {
|
|
form.value[field] = invalid
|
|
assert.notEqual(validate(), '', `${field}=${invalid} must fail`)
|
|
}
|
|
for (const valid of [0, '0', 1.25, '', null]) {
|
|
form.value[field] = valid
|
|
assert.equal(validate(), '')
|
|
}
|
|
form.value[field] = 0
|
|
}
|
|
for (const invalid of [0, 366, Infinity, 'invalid']) {
|
|
form.value.validityDays = invalid
|
|
assert.notEqual(validate(), '', `validity=${invalid} must fail`)
|
|
}
|
|
for (const valid of [1, 365]) {
|
|
form.value.validityDays = valid
|
|
assert.equal(validate(), '')
|
|
}
|
|
})
|
|
|
|
test('quote customer navigation preserves approval and contract origins using fixed mobile routes', () => {
|
|
const nav = navigation as Record<string, any>
|
|
assert.equal(typeof nav.mpQuoteCustomerLocation, 'function')
|
|
assert.equal(typeof nav.mpRelatedQuoteReturnLocation, 'function')
|
|
for (const origin of [
|
|
{},
|
|
{ from: 'approve' },
|
|
{
|
|
from: 'contract',
|
|
returnContractId: 'K-1',
|
|
originCustomerId: 'C-0'
|
|
}
|
|
]) {
|
|
const location = nav.mpQuoteCustomerLocation({ id: 'Q-1', customerId: 'C-1' }, origin)
|
|
assert.equal(location.path, '/m/crm/customer/C-1')
|
|
assert.deepEqual(nav.mpRelatedQuoteReturnLocation(location.query), {
|
|
path: '/m/crm/quote/Q-1',
|
|
query: origin
|
|
})
|
|
}
|
|
assert.equal(nav.mpQuoteCustomerLocation({ id: 'Q', customerId: '../bad' }, {}), null)
|
|
assert.equal(nav.mpRelatedQuoteReturnLocation({ from: 'quote', returnQuoteId: '//evil' }), null)
|
|
})
|
|
|
|
test('quote customer click is guarded and customer back uses the quote return destination', () => {
|
|
const targets: any[] = []
|
|
let ready = false
|
|
const goCustomer = handler('views/m/crm/quote/detail.vue', 'goCustomer', {
|
|
navigationReady: () => ready,
|
|
quote: { value: { id: 'Q', customerId: 'C' } },
|
|
route: { query: { from: 'approve' } },
|
|
router: { push: (v: any) => targets.push(v) },
|
|
mpQuoteCustomerLocation: (navigation as any).mpQuoteCustomerLocation
|
|
})
|
|
goCustomer()
|
|
assert.equal(targets.length, 0)
|
|
ready = true
|
|
goCustomer()
|
|
assert.equal(targets[0].path, '/m/crm/customer/C')
|
|
const destination = { path: '/m/crm/quote/Q', query: { from: 'approve' } }
|
|
const back = handler('views/m/crm/customer/detail.vue', 'back', {
|
|
relatedContractReturn: { value: null },
|
|
relatedQuoteReturn: { value: destination },
|
|
router: { replace: (v: any) => targets.push(v) },
|
|
CUSTOMER_PATH: '/m/crm/customer'
|
|
})
|
|
back()
|
|
assert.deepEqual(targets[1], destination)
|
|
})
|