变更问题修复
This commit is contained in:
1 parent
6de4422733
commit
9625110f44
62 files changed
+18116
-95
No files matched your search
@@ -6,6 +6,7 @@ import { createRequire } from 'node:module';
|
||||
import { validateStandardOperation, validateProgramOperation } from '../LianSyn-platform/external-agent-client.mjs';
|
||||
import Ajv from 'ajv/dist/2020.js';
|
||||
import addFormats from 'ajv-formats';
|
||||
import { loadPageActionRealm } from './page-action-test-realm.mjs';
|
||||
const plans = createRequire(import.meta.url)('../chrome-extension/ltjt-order-assistant/operation-plans.js');
|
||||
const ajv = new Ajv({ strict: false }); addFormats(ajv);
|
||||
const parsedSchema = ajv.compile(JSON.parse(readFileSync(new URL('../schemas/agent_operation.schema.json', import.meta.url))));
|
||||
@@ -18,7 +19,7 @@ const adapter = readFileSync(new URL('../chrome-extension/ltjt-order-assistant/l
|
||||
assistant.testOperationBlockers = operationBlockers; assistant.testExpected = arrangementExpectedFields;
|
||||
assistant.testResource = arrangementResourceProof; assistant.testNative = applyNativeSettlementSelection;
|
||||
assistant.preflightLifecycleOperation = preflightLifecycleOperation;`);
|
||||
function fixture(type, { index = type === 'guide' ? 0 : 1, duplicate = false, zeroQuantity = false, onSelection = () => {}, rows } = {}) {
|
||||
function fixture(type, { index = type === 'guide' ? 0 : 1, duplicate = false, zeroQuantity = false, onSelection = () => {}, rows, omitDateMatcher = false } = {}) {
|
||||
let now = 10000, selections = 0;
|
||||
const fields = new Map(), form = { elements: [], id: 'InfoForm1', isConnected: true };
|
||||
const document = { querySelector: () => form, querySelectorAll: () => [], readyState: 'complete' };
|
||||
@@ -56,7 +57,7 @@ function fixture(type, { index = type === 'guide' ? 0 : 1, duplicate = false, ze
|
||||
const sandbox = { window, document, Event: window.Event, URL, URLSearchParams, TextEncoder,
|
||||
Date: class extends Date { static now() { return now; } }, setTimeout(cb,ms) { now += ms; cb(); } };
|
||||
window.setTimeout = sandbox.setTimeout;
|
||||
vm.runInNewContext(inpage,sandbox); vm.runInNewContext(adapter,sandbox);
|
||||
loadPageActionRealm(window, sandbox, { 'inpage.js': inpage, 'lifecycle-adapters.js': adapter }, omitDateMatcher ? ['operation-plans.js'] : []);
|
||||
const changes = { [type === 'guide' ? 'resource' : 'supplier']: { name: '测试新资源', keyword: '测试新资源' }, ...(['vehicle','transport'].includes(type) ? { quantity: 2 } : {}) };
|
||||
const selection = type === 'guide' ? undefined : type === 'vehicle' ? { start_date: '2026-09-15', end_date: '2026-09-16' } : { date: '2026-09-15' };
|
||||
const input = { action: `arrangement_${type}`, order_nature: 'formal', submit_mode: 'dry_run', data: { existing_refs: { identifier: 'LW-TEST-UPDATE', kind: 'shared_plan' }, arrangement: { mode: 'update', ...(selection ? { selection } : {}), changes } } };
|
||||
@@ -66,6 +67,20 @@ function fixture(type, { index = type === 'guide' ? 0 : 1, duplicate = false, ze
|
||||
return { api, form, fields, input, selections: () => selections };
|
||||
}
|
||||
const types = ['guide','vehicle','transport','other'];
|
||||
test('dated updates report missing MAIN-world dependency without changing native fields; guide stays independent', () => {
|
||||
for (const type of types) {
|
||||
const f = fixture(type, { omitDateMatcher: true });
|
||||
const before = [...f.fields].map(([key, control]) => [key, control.value]);
|
||||
const result = f.api.testResolve(f.form, f.input);
|
||||
if (type === 'guide') assert.equal(result.ok, true, JSON.stringify(result));
|
||||
else {
|
||||
assert.equal(result.ok, false);
|
||||
assert.deepEqual(Array.from(result.blockers), ['arrangement_date_matcher_unavailable']);
|
||||
}
|
||||
assert.equal(f.selections(), 0);
|
||||
assert.deepEqual([...f.fields].map(([key, control]) => [key, control.value]), before);
|
||||
}
|
||||
});
|
||||
for (const type of types) test(`${type} update resolves the original record and preserves dates and unspecified fields`, async () => {
|
||||
for (const index of type === 'guide' ? [0] : [0,1,10]) {
|
||||
const f = fixture(type,{index});
|
||||
@@ -395,3 +410,62 @@ test('native transport selection rechecks a filter even after preflight and neve
|
||||
assert.deepEqual([...f.fields.values()].map(c => c.value), before);
|
||||
}
|
||||
});
|
||||
|
||||
for (const type of ['vehicle','transport','other']) test(`${type} month/day dates pass parsed contracts and resolve to a full-year execution snapshot`, () => {
|
||||
const f = fixture(type);
|
||||
f.input.data.arrangement.selection = type === 'vehicle' ? { start_date:'09-15',end_date:'09-16' } : {date:'09-15', ...(type === 'other' ? {filing_date:'09-14'} : {})};
|
||||
assert.equal(parsedSchema(f.input), true, JSON.stringify(parsedSchema.errors));
|
||||
assert.deepEqual(validateProgramOperation(f.input), []);
|
||||
assert.equal(plans.validateDispatchOperation(f.input).blockers.length, 0);
|
||||
const resolved = f.api.testResolve(f.form, f.input);
|
||||
assert.equal(resolved.ok, true, JSON.stringify(resolved));
|
||||
assert.equal(executionSchema(resolved.operation), true, JSON.stringify(executionSchema.errors));
|
||||
assert.equal(resolved.operation.data.arrangement[type === 'vehicle' ? 'start_date' : 'date'], '2026-09-15');
|
||||
assert.equal(resolved.operation.data.arrangement.selection, undefined);
|
||||
f.fields.get('riqi0').value = '2027-9-15'; f.fields.get('riqis0').value = '2027-9-16';
|
||||
assert.equal(f.api.testResolve(f.form, f.input).ok, false, 'two years are ambiguous');
|
||||
f.input.data.arrangement.selection[type === 'vehicle' ? 'start_date' : 'date'] = '2026-09-15';
|
||||
assert.equal(f.api.testResolve(f.form, f.input).ok, true);
|
||||
if (type === 'other') {
|
||||
f.input.data.arrangement.selection.filing_date = '2027-09-14';
|
||||
assert.equal(f.api.testResolve(f.form, f.input).ok, false, 'explicit filing year must match');
|
||||
}
|
||||
});
|
||||
|
||||
test('parsed date-selector validators agree on invalid calendars while execution still requires a full year', () => {
|
||||
for (const invalid of ['02-30','13-01','2026-02-29','9-15','bad']) {
|
||||
const f = fixture('transport'); f.input.data.arrangement.selection.date = invalid;
|
||||
assert.equal(parsedSchema(f.input), false, invalid);
|
||||
assert.ok(validateProgramOperation(f.input).length, invalid);
|
||||
assert.ok(plans.validateDispatchOperation(f.input).blockers.length, invalid);
|
||||
}
|
||||
assert.equal(plans.matchesOriginalArrangementDate('2028-02-29', '02-29'), true);
|
||||
assert.equal(plans.matchesOriginalArrangementDate('2027-02-29', '02-29'), false);
|
||||
const f = fixture('transport'); const resolved = f.api.testResolve(f.form, f.input).operation;
|
||||
resolved.data.arrangement.date = '09-15';
|
||||
assert.equal(executionSchema(resolved), false);
|
||||
assert.ok(validateStandardOperation(resolved).length);
|
||||
});
|
||||
|
||||
test('ambiguous original dates are surfaced in the route failure message without native ids', () => {
|
||||
const source = readFileSync(new URL('../chrome-extension/ltjt-order-assistant/background.js', import.meta.url), 'utf8');
|
||||
const start = source.indexOf('function lifecycleRouteFailure(');
|
||||
const end = source.indexOf('\nasync function executeLifecycleOperation', start);
|
||||
const failure = vm.runInNewContext(`(${source.slice(start,end).trim()})`);
|
||||
const unavailable = failure({action:'arrangement_hotel'}, {blockers:['arrangement_date_matcher_unavailable']});
|
||||
assert.equal(unavailable.errorCode, 'arrangement_date_matcher_unavailable');
|
||||
assert.match(unavailable.message, /插件日期匹配组件未加载/);
|
||||
assert.doesNotMatch(unavailable.message, /没有找到|核对原安排/);
|
||||
const absent = failure({action:'arrangement_hotel'}, {blockers:['arrangement_update_target_candidate_count:0']});
|
||||
assert.equal(absent.errorCode, 'arrangement_update_target_not_unique');
|
||||
assert.match(absent.message, /没有找到/);
|
||||
const result = failure({action:'arrangement_hotel'}, {blockers:['arrangement_update_target_candidate_count:2'], preflight:{resource_resolution:{candidates:[
|
||||
{date:'2026-09-04',end_date:'2026-09-05',resource:'原酒店',item:'TWN'},
|
||||
{date:'2027-09-04',end_date:'2027-09-05',resource:'原酒店',item:'TWN'}
|
||||
]}}});
|
||||
assert.match(result.message,/2026-09-04 至 2026-09-05/);
|
||||
assert.match(result.message,/2027-09-04 至 2027-09-05/);
|
||||
assert.match(result.message,/完整年月日重新提交/);
|
||||
assert.match(result.message,/未写入 ERP/);
|
||||
assert.match(inpage,/resource_resolution: arrangementResolution.evidence/);
|
||||
});
|
||||
Reference in new issue
Block a user