const { test } = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const vm = require('node:vm') const ts = require('typescript') const dayjs = require('dayjs') const { parse } = require('@vue/compiler-sfc') const { descriptor } = parse(fs.readFileSync(`${__dirname}/../pages/createDocument/edit/[[id]].vue`, 'utf8')) const script = ts.createSourceFile('document-editor.js', descriptor.scriptSetup.content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS) const handlers = new Set(['normalizeEntityId', 'normalizeUnitId', 'normalizeCreatedDocumentRow', 'normalizeCreatedDocumentRows', 'normalizeTaxTypeValue', 'originalDocumentType', 'canUseAdvanceInvoice', 'validateAdvanceInvoiceCreation', 'setupPage', 'setRowData']) const source = script.statements .filter(statement => ts.isVariableStatement(statement) && statement.declarationList.declarations.some(declaration => handlers.has(declaration.name.getText(script)))) .map(statement => statement.getText(script)).join('\n') function fixture(unit) { const ref = value => ({ value }) const product = { id: 20, name: 'Artikel', unit, selling_price: 10, tax_percentage: 19 } const service = { id: 30, name: 'Leistung', unit, sellingPrice: 20, sellingPriceComposed: {}, taxPercentage: 19 } const context = vm.createContext({ ref, computed: getter => ({ get value() { return getter() } }), isTemplateMode: ref(false), dayjs, uuidv4: () => 'row-id', console: { log() {} }, products: ref([product]), services: ref([service]), productcategories: ref([]), servicecategories: ref([]), itemInfo: ref({ type: 'invoices', taxType: 'Standard', rows: [], agriculture: {} }), route: { params: {}, query: {} }, loaded: ref(false), templateName: ref(''), taxTypeItems: [{ key: 'Standard' }], dataStore: { documentTypesForCreation: { invoices: { labelSingle: 'Rechnung' } } }, setupData: async () => {}, setDocumentTypeConfig() {}, setContactPersonData: async () => {}, checkCompatibilityWithInputPrice() {}, updateCustomSurcharge() {}, useEntities: relation => ({ select: async () => relation === 'products' ? [product] : [service], selectSingle: async () => { if (relation === 'documenttemplates') return { name: 'Vorlage', documentType: 'invoices', templateData: { rows: [{ id: 'saved-row', mode: 'normal', product: 20, unit }] } } return { id: 40, type: 'invoices', taxType: 'Standard', rows: [{ id: 'saved-row', mode: 'normal', product: 20, unit }] } }, }), }) vm.runInContext(source, context) return { context, run: code => vm.runInContext(code, context) } } const formats = [1, { id: 1, name: 'Stück' }, '1', { id: '1', name: 'Stück' }] test('article and service selection resolve relation objects and legacy IDs to a selectable unit', async () => { for (const unit of formats) { const { run } = fixture(unit) for (const entity of ['product', 'service']) { run(`itemInfo.value.rows = [{ ${entity}: ${entity === 'product' ? 20 : 30} }]`) await run('setRowData(itemInfo.value.rows[0])') assert.equal(run('itemInfo.value.rows[0].unit'), 1, `${entity}: ${JSON.stringify(unit)}`) } } }) test('article and service modal results retain their selected unit', async () => { for (const unit of formats) { const { run } = fixture(unit) run('itemInfo.value.rows = [{}]') await run('setRowData(itemInfo.value.rows[0], null, products.value[0])') assert.equal(run('itemInfo.value.rows[0].unit'), 1) run('itemInfo.value.rows = [{}]') await run('setRowData(itemInfo.value.rows[0], services.value[0], null)') assert.equal(run('itemInfo.value.rows[0].unit'), 1) } }) test('saved documents and both template entry points restore units without overwriting the stored choice', async () => { for (const route of [{ params: { id: 40 }, query: {} }, { params: {}, query: { templateId: 50 } }, { params: {}, query: { templateFromDocument: 40 } }]) { for (const unit of formats) { const { context, run } = fixture(unit) context.route = route context.products.value[0].unit = { id: 2, name: 'Meter' } await run('setupPage()') assert.equal(run('loaded.value'), true) assert.equal(run('itemInfo.value.rows[0].unit'), 1, JSON.stringify(route)) assert.equal(run('itemInfo.value.rows[0].id'), 'saved-row') } } }) test('imported JSON rows preserve quantity, prices and the stored unit', () => { const { run, context } = fixture(1) context.rows = [JSON.stringify({ id: 'imported', mode: 'normal', unit: { id: '1' }, quantity: 2.5, price: 12.34 })] const row = run('normalizeCreatedDocumentRows(rows)[0]') assert.equal(row.unit, 1) assert.equal(row.id, 'imported') assert.equal(row.quantity, 2.5) assert.equal(row.price, 12.34) }) test('missing and malformed units remain unselected', () => { const { run, context } = fixture(1) for (const unit of [null, undefined, '', {}, { id: null }, 'invalid', 0, -1, true]) { context.row = { unit } assert.equal(run('normalizeCreatedDocumentRow(row).unit'), null) } })