判断修改
This commit is contained in:
1 parent
e06afc8c33
commit
4194a200c1
65 files changed
+9617
-109
No files matched your search
@@ -14,7 +14,7 @@ const testSource = adapterSource.replace(
|
||||
);
|
||||
const hotelFields = ['riqi0', 'riqis0', 'danwei0', 'danweiid0', 'fangxing0', 'jianshu0', 'zt0', 'beizhu0', 'id0', 'yf0', 'sh0', 'MaxI', 'tdID', 'ddID', 'chufari', 'SubmitButton'];
|
||||
|
||||
function fixture({ count = 154, maxI = '6', mode = 'create', tick = () => {}, proofs } = {}) {
|
||||
function fixture({ count = 76, maxI = '2', rows = Number(maxI) || 2, mode = 'create', tick = () => {}, proofs } = {}) {
|
||||
let now = 10000;
|
||||
const initialTime = now;
|
||||
const values = { MaxI: maxI, tdID: '123', ddID: '0', chufari: '2026-09-15' };
|
||||
@@ -23,8 +23,11 @@ function fixture({ count = 154, maxI = '6', mode = 'create', tick = () => {}, pr
|
||||
disabled: false, value: values[name] ?? ''
|
||||
});
|
||||
const form = { id: 'InfoForm1', isConnected: true, elements: hotelFields.map(field) };
|
||||
for (let i = hotelFields.length - 1; i < count; i += 1) form.elements.push(field(`extra${i}`));
|
||||
const state = { loading: false };
|
||||
for (let row = 1; row < rows; row += 1) {
|
||||
form.elements.push(...hotelFields.filter((name) => name.endsWith('0')).map((name) => field(`${name.slice(0, -1)}${row}`)));
|
||||
}
|
||||
for (let i = form.elements.length - 1; i < count; i += 1) form.elements.push(field(`extra${i}`));
|
||||
const state = { loading: false, currentForm: form };
|
||||
const loadingElement = {
|
||||
className: 'datagrid-mask',
|
||||
getBoundingClientRect: () => ({ width: 50, height: 50, left: 0, top: 0, right: 50, bottom: 50 }),
|
||||
@@ -32,7 +35,7 @@ function fixture({ count = 154, maxI = '6', mode = 'create', tick = () => {}, pr
|
||||
};
|
||||
const document = {
|
||||
querySelectorAll: (selector) => selector.startsWith('.datagrid-mask') && state.loading ? [loadingElement] : [],
|
||||
querySelector: () => form,
|
||||
querySelector: () => state.currentForm,
|
||||
readyState: 'complete'
|
||||
};
|
||||
const window = {
|
||||
@@ -59,11 +62,13 @@ function fixture({ count = 154, maxI = '6', mode = 'create', tick = () => {}, pr
|
||||
};
|
||||
}
|
||||
|
||||
test('hotel create accepts the reported complete 154-field form after one stable second', async () => {
|
||||
test('hotel create accepts a complete two-row 76-field form after one stable second', async () => {
|
||||
const page = fixture();
|
||||
const result = await page.run();
|
||||
assert.equal(result.successful_control_count, 154);
|
||||
assert.equal(result.successful_control_count, 76);
|
||||
assert.equal(result.ready, true, JSON.stringify(result.blockers));
|
||||
assert.equal(result.hotel_row_count, 2);
|
||||
assert.equal(result.native_max_i, 2);
|
||||
assert.ok(page.elapsed() >= 1000 && page.elapsed() < 2000);
|
||||
});
|
||||
|
||||
@@ -74,13 +79,12 @@ test('hotel create fails closed without a form', async () => {
|
||||
assert.ok(missing.blockers.includes('lifecycle_complete_form_missing'));
|
||||
});
|
||||
|
||||
test('hotel create uses the requested 150-field boundary', async () => {
|
||||
for (const count of [149, 150, 154, 195, 442]) {
|
||||
const result = await fixture({ count }).run();
|
||||
test('hotel create accepts complete variable-size forms without a serialized count threshold', async () => {
|
||||
for (const [count, maxI] of [[76, '2'], [149, '5'], [150, '5'], [154, '5'], [195, '7'], [442, '16']]) {
|
||||
const result = await fixture({ count, maxI }).run();
|
||||
assert.equal(result.successful_control_count, count);
|
||||
assert.equal(result.minimum_successful_controls, 150);
|
||||
assert.equal(result.ready, count >= 150, `${count}: ${JSON.stringify(result.blockers)}`);
|
||||
if (count < 150) assert.ok(result.blockers.includes(`lifecycle_form_incomplete:${count}:150`));
|
||||
assert.equal(result.minimum_successful_controls, null);
|
||||
assert.equal(result.ready, true, `${count}: ${JSON.stringify(result.blockers)}`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -106,7 +110,7 @@ test('hotel create waits for visible loading to disappear and then stabilize', a
|
||||
assert.ok(result.blockers.includes('lifecycle_loading_overlay_visible'));
|
||||
});
|
||||
|
||||
test('hotel create retains the existing one-second count stability gate', async () => {
|
||||
test('hotel create requires a full observed stable second, including the final timeout sample', async () => {
|
||||
const grow = (form) => form.elements.push({ name: `extra${form.elements.length}`, tagName: 'INPUT', type: 'text', value: '' });
|
||||
const settling = fixture({ tick: ({ elapsed, form }) => { if (elapsed === 750) grow(form); } });
|
||||
assert.equal((await settling.run()).ready, true);
|
||||
@@ -115,6 +119,10 @@ test('hotel create retains the existing one-second count stability gate', async
|
||||
const result = await changing.run();
|
||||
assert.equal(result.ready, false);
|
||||
assert.ok(result.blockers.includes('lifecycle_form_not_stable'));
|
||||
assert.equal((await fixture().run(999)).ready, false);
|
||||
assert.equal((await fixture().run(1000)).ready, true);
|
||||
const lastSample = fixture({ tick: ({ elapsed, form }) => { if (elapsed === 1000) grow(form); } });
|
||||
assert.equal((await lastSample.run(1000)).ready, false);
|
||||
});
|
||||
|
||||
test('hotel update/clear and unrelated lifecycle actions retain their current count gates', async () => {
|
||||
@@ -132,7 +140,7 @@ test('hotel update/clear and unrelated lifecycle actions retain their current co
|
||||
assert.equal(result.minimum_successful_controls, 90);
|
||||
});
|
||||
|
||||
test('154-field readiness still leaves occupied slots and payment/audit state blocked', async () => {
|
||||
test('76-field readiness still leaves occupied slots and payment/audit state blocked', async () => {
|
||||
for (const [name, value, blocker] of [
|
||||
['id0', '1234', 'arrangement_slot_occupied:id0'],
|
||||
['danweiid0', '5678', 'arrangement_slot_occupied:danweiid0'],
|
||||
@@ -148,7 +156,7 @@ test('154-field readiness still leaves occupied slots and payment/audit state bl
|
||||
}
|
||||
});
|
||||
|
||||
test('full hotel preflight preserves identity, resource and ownership gates after the count check', async () => {
|
||||
test('full hotel preflight preserves identity, resource and ownership gates after structural readiness', async () => {
|
||||
for (const failure of ['', 'identity', 'resource', 'ownership', 'slot']) {
|
||||
const calls = [];
|
||||
const page = fixture({ proofs: {
|
||||
@@ -174,3 +182,81 @@ test('full hotel preflight preserves identity, resource and ownership gates afte
|
||||
assert.equal(result.write_attempted, false);
|
||||
}
|
||||
});
|
||||
|
||||
test('hotel create rejects missing controls in later rows even on a large form', async () => {
|
||||
for (const name of hotelFields.filter((name) => name.endsWith('0')).map((name) => `${name.slice(0, -1)}1`)) {
|
||||
const page = fixture({ count: 442 });
|
||||
page.form.elements = page.form.elements.filter((control) => control.name !== name);
|
||||
const result = await page.run();
|
||||
assert.equal(result.ready, false, name);
|
||||
assert.ok(result.missing_required_fields.includes(name), name);
|
||||
}
|
||||
});
|
||||
|
||||
test('hotel create rejects invalid row markers, omitted rows and gaps', async () => {
|
||||
for (const maxI of ['', '0', '-1', '2.5', '2x', 'Infinity', '9007199254740992']) {
|
||||
const result = await fixture({ maxI, rows: 2 }).run();
|
||||
assert.equal(result.ready, false, maxI);
|
||||
assert.ok(result.blockers.includes('lifecycle_hotel_max_i_invalid'));
|
||||
}
|
||||
for (const [maxI, rows] of [['3', 2], ['1', 2], ['999999999', 2]]) {
|
||||
const result = await fixture({ maxI, rows }).run();
|
||||
assert.equal(result.ready, false);
|
||||
assert.ok(result.blockers.includes(`lifecycle_hotel_rows_incomplete:${rows}:${maxI}`));
|
||||
}
|
||||
const gap = fixture({ maxI: '3' });
|
||||
gap.form.elements = gap.form.elements.filter((control) => !/^(riqi|riqis|danwei|danweiid|fangxing|jianshu|zt|beizhu|id|yf|sh)1$/.test(control.name));
|
||||
assert.equal((await gap.run()).ready, false);
|
||||
});
|
||||
|
||||
test('hotel create rejects disabled, duplicate and id-only required data controls', async () => {
|
||||
for (const change of [
|
||||
(control) => { control.disabled = true; },
|
||||
(control) => { control.matches = (selector) => selector === ':disabled'; },
|
||||
(control, form) => { form.elements.push({ ...control }); },
|
||||
(control) => { control.name = ''; },
|
||||
(control) => { control.type = 'button'; },
|
||||
(control) => { control.isConnected = false; }
|
||||
]) {
|
||||
const page = fixture();
|
||||
change(page.form.elements.find((control) => control.name === 'jianshu0'), page.form);
|
||||
const result = await page.run();
|
||||
assert.equal(result.ready, false);
|
||||
assert.ok(result.unavailable_required_fields.includes('jianshu0'));
|
||||
}
|
||||
const readonly = fixture();
|
||||
readonly.form.elements.find((control) => control.name === 'fangxing0').readOnly = true;
|
||||
assert.equal((await readonly.run()).ready, true);
|
||||
});
|
||||
|
||||
test('hotel create rejects detached or replaced forms and unfinished documents', async () => {
|
||||
for (const change of [
|
||||
(page) => { page.form.isConnected = false; },
|
||||
(page) => { page.state.currentForm = { ...page.form }; },
|
||||
(page) => { page.form.ownerDocument.readyState = 'loading'; }
|
||||
]) {
|
||||
const page = fixture();
|
||||
change(page);
|
||||
assert.equal((await page.run()).ready, false);
|
||||
}
|
||||
});
|
||||
|
||||
test('same-count control replacement and select-option changes restart stability', async () => {
|
||||
for (const change of [
|
||||
(form) => { form.elements[0] = { ...form.elements[0] }; },
|
||||
(form) => { form.elements.at(-1).id += 'changed'; },
|
||||
(form) => { form.elements.at(-1).options = [{}]; }
|
||||
]) {
|
||||
const page = fixture({ tick: ({ elapsed, form }) => { if (elapsed === 750) change(form); } });
|
||||
assert.equal((await page.run()).ready, true);
|
||||
assert.equal(page.elapsed(), 1750);
|
||||
}
|
||||
});
|
||||
|
||||
test('native pending ajax blocks hotel readiness even without a visible overlay', async () => {
|
||||
const page = fixture();
|
||||
page.form.ownerDocument.defaultView.jQuery = { active: 1 };
|
||||
const result = await page.run();
|
||||
assert.equal(result.ready, false);
|
||||
assert.equal(result.native_ajax_active, true);
|
||||
});
|
||||
Reference in new issue
Block a user