83 lines
4.6 KiB
JavaScript
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'));
|
|
}
|
|
});
|