Files
LWLT-AIBOT/tools/passenger-tsv.test.mjs
2026-09-10 17:30:27 +08:00

83 lines
4.6 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { createRequire } from 'node:module';
import test from 'node:test';
import vm from 'node:vm';
import { validateProgramOperation } from '../LianSyn-platform/external-agent-client.mjs';
const require = createRequire(import.meta.url);
const plans = require('../chrome-extension/ltjt-order-assistant/operation-plans.js');
const headers = plans.PASSENGER_HEADERS.join('\t');
const row = (sequence, phone = '13800000001', remark = '') => [
sequence, `合成游客${sequence}`, 'SYNTHETIC GUEST', '男', '1990-01-01', '合成城市',
'护照', `TEST-PASS-${sequence}`, '合成城市', '2025-01-01', '2035-01-01', phone, remark
].join('\t');
const operation = (text, rowCount = 1, kind = 'independent_order') => ({
action: 'passenger_list_import', order_nature: 'formal', submit_mode: 'dry_run',
data: {
existing_refs: { kind, identifier: 'SYNTH-ORDER-001' },
passenger_list: { operation: 'import', row_count: rowCount, text }
}
});
test('passenger TSV keeps trailing empty columns through server and plugin dispatch', () => {
for (const kind of ['independent_order', 'shared_child_order']) {
for (const phone of ['13800000001', '']) {
const text = [headers, ...Array.from({ length: 19 }, (_, i) => row(i + 1, phone))].join('\n');
for (const input of [text, `\r\n${text.replace(/\n/g, '\r\n')}\r\n\r\n`]) {
for (const mode of ['import', 'full_replace']) {
const candidate = operation(input, 19, kind);
Object.assign(candidate.data.passenger_list, mode === 'full_replace'
? { operation: mode, confirmed: true } : { operation: mode });
assert.deepEqual(validateProgramOperation(candidate), []);
assert.deepEqual(plans.validateDispatchOperation(candidate).blockers, []);
assert.equal(plans.buildPassengerTsv(candidate.data.passenger_list), text);
assert.equal(candidate.data.passenger_list.text, input);
}
}
}
}
});
test('passenger TSV still rejects missing or surplus columns and keeps leader validation', () => {
for (const malformed of [row(1).slice(0, -1), `${row(1)}\t`]) {
const candidate = operation(`${headers}\n${malformed}`);
assert.match(validateProgramOperation(candidate).join('\n'), /完整 13 列/);
assert.match(plans.validateDispatchOperation(candidate).blockers.join('\n'), /13 列/);
}
const candidate = operation(`${headers}\n${row(1, '13800000001', '领队')}\n${row(2, '')}`, 2);
assert.match(validateProgramOperation(candidate).join('\n'), /leader_contact/);
assert.match(plans.validateDispatchOperation(candidate).blockers.join('\n'), /leader_contact/);
candidate.data.passenger_list.leader_contact = { sequence: 1, name: '合成游客1', phone: '13800000001' };
assert.deepEqual(validateProgramOperation(candidate), []);
assert.deepEqual(plans.validateDispatchOperation(candidate).blockers, []);
candidate.data.passenger_list.leader_contact.phone = '13800000002';
assert.match(validateProgramOperation(candidate).join('\n'), /完全一致/);
assert.match(plans.validateDispatchOperation(candidate).blockers.join('\n'), /完全一致/);
});
test('passenger merge accepts empty final fields without repairing malformed column counts', async () => {
const source = await readFile(new URL('../chrome-extension/ltjt-order-assistant/lifecycle-adapters.js', import.meta.url), 'utf8');
const sandbox = { window: { LTJTOrderAssistant: {} } };
vm.runInNewContext(source, sandbox);
const merge = sandbox.window.LTJTOrderAssistant.planPassengerMerge;
const blankRows = Array.from({ length: 19 }, (_, i) => Object.fromEntries(plans.PASSENGER_HEADERS.map(header => [
header, header === '序号' ? i + 1 : header === '证件类型' ? '护照' : ''
])));
for (const phone of ['13800000001', '']) {
const text = [headers, ...Array.from({ length: 19 }, (_, i) => row(i + 1, phone))].join('\n');
for (const input of [text, `\r\n${text.replace(/\n/g, '\r\n')}\r\n`]) {
const result = merge(blankRows, { operation: 'first_import', row_count: 19, text: input }, 19);
assert.deepEqual([...result.blockers], []);
assert.equal(result.merged_tsv, text);
assert.equal(result.input_rows[18]['电话'], phone);
assert.equal(result.input_rows[18]['备注'], '');
assert.equal(result.changed_sequences.length, 19);
}
}
for (const malformed of [row(1).slice(0, -1), `${row(1)}\t`]) {
const result = merge(blankRows, { operation: 'first_import', row_count: 1, text: `${headers}\n${malformed}` }, 19);
assert.ok(result.blockers.includes('passenger_input_row_columns_incomplete'));
}
});