172 lines
5.2 KiB
JavaScript
172 lines
5.2 KiB
JavaScript
const test = require('node:test');
|
||
const assert = require('node:assert/strict');
|
||
|
||
const submitGuard = require('../erp_submit_guard');
|
||
|
||
function fakePage({ bodyText = '', ajaxEvents = [], onSubmit } = {}) {
|
||
const calls = { submit: 0, waits: 0, waitMs: [], ajaxProbe: [] };
|
||
return {
|
||
calls,
|
||
async evaluate(fn, arg) {
|
||
const text = String(fn);
|
||
if (text.includes('__erpSubmitAjaxMinimumTimeout')) {
|
||
calls.ajaxProbe.push(arg);
|
||
return { installed: true, minimumTimeout: arg };
|
||
}
|
||
if (text.includes('__erpSubmitAjaxEvents')) return ajaxEvents;
|
||
if (text.includes('SubmitInfoForm')) {
|
||
calls.submit += 1;
|
||
if (onSubmit) onSubmit();
|
||
return null;
|
||
}
|
||
if (text.includes('document.body.innerText')) return bodyText;
|
||
return bodyText;
|
||
},
|
||
async waitForTimeout(ms) {
|
||
calls.waits += 1;
|
||
calls.waitMs.push(ms);
|
||
},
|
||
};
|
||
}
|
||
|
||
test('submitInfoFormAndConfirm accepts a confirmed ERP update save', async () => {
|
||
const dialogState = {
|
||
messages: [{ type: 'alert', message: '您还没有登录或登录超时,请重新登陆!' }],
|
||
};
|
||
const page = fakePage({
|
||
bodyText: '警告 × 修改成功/ความสำเร็จ! 修改团队 应收团款',
|
||
});
|
||
|
||
const result = await submitGuard.submitInfoFormAndConfirm(page, dialogState, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
});
|
||
|
||
assert.equal(result.ok, true);
|
||
assert.equal(page.calls.submit, 1);
|
||
assert.equal(page.calls.waits, 1);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm uses a longer default wait for slow ERP submit responses', async () => {
|
||
const page = fakePage({
|
||
bodyText: 'success',
|
||
});
|
||
|
||
await submitGuard.submitInfoFormAndConfirm(page, { messages: [] }, {
|
||
source: 'test.update',
|
||
});
|
||
|
||
assert.deepEqual(page.calls.waitMs, [30000]);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm raises the ERP ajax timeout before saving', async () => {
|
||
const page = fakePage({
|
||
bodyText: 'success',
|
||
ajaxEvents: [{ event: 'success', status: 200, responseText: 'success' }],
|
||
});
|
||
|
||
const result = await submitGuard.submitInfoFormAndConfirm(page, { messages: [] }, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
ajaxTimeoutMs: 45000,
|
||
});
|
||
|
||
assert.equal(result.ok, true);
|
||
assert.deepEqual(page.calls.ajaxProbe, [45000]);
|
||
assert.deepEqual(result.ajaxEvents, [{ event: 'success', status: 200, responseText: 'success' }]);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm includes ERP ajax failure details when submit is unconfirmed', async () => {
|
||
const page = fakePage({
|
||
bodyText: '璀﹀憡 error锛?',
|
||
ajaxEvents: [{
|
||
event: 'error',
|
||
status: 0,
|
||
textStatus: 'timeout',
|
||
error: 'timeout',
|
||
timeout: 45000,
|
||
responseText: '',
|
||
}],
|
||
});
|
||
|
||
await assert.rejects(
|
||
() => submitGuard.submitInfoFormAndConfirm(page, { messages: [] }, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
ajaxTimeoutMs: 45000,
|
||
}),
|
||
(error) => {
|
||
assert.equal(error.code, 'erp_submit_unconfirmed');
|
||
assert.deepEqual(error.details.ajaxEvents, [{
|
||
event: 'error',
|
||
status: 0,
|
||
textStatus: 'timeout',
|
||
error: 'timeout',
|
||
timeout: 45000,
|
||
responseText: '',
|
||
}]);
|
||
return true;
|
||
}
|
||
);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm does not treat background ajax success events as save confirmation', async () => {
|
||
const page = fakePage({
|
||
bodyText: '淇敼鍥㈤槦 搴旀敹鍥㈡',
|
||
ajaxEvents: [{
|
||
event: 'success',
|
||
url: '../dat/AjaxPublicFun.asp?Act=GetSFXiangMu&sf=0',
|
||
status: 200,
|
||
textStatus: 'success',
|
||
responseText: '成人团费◇小孩占床团费',
|
||
}],
|
||
});
|
||
|
||
await assert.rejects(
|
||
() => submitGuard.submitInfoFormAndConfirm(page, { messages: [] }, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
}),
|
||
(error) => error.code === 'erp_submit_unconfirmed'
|
||
);
|
||
});
|
||
|
||
test('isPrimarySubmitAjaxEvent recognizes split-plan save endpoint', () => {
|
||
assert.equal(submitGuard.isPrimarySubmitAjaxEvent({ url: '/System/DAT/plan.asp' }), true);
|
||
assert.equal(submitGuard.isPrimarySubmitAjaxEvent({ url: 'https://ltjt.yunzhi.run/System/DAT/plan.asp' }), true);
|
||
assert.equal(submitGuard.isPrimarySubmitAjaxEvent({ url: '../dat/AjaxPublicFun.asp?Act=GetSFXiangMu&sf=0' }), false);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm rejects a fresh login-timeout prompt after submit', async () => {
|
||
const dialogState = { messages: [] };
|
||
const page = fakePage({
|
||
bodyText: '修改团队 应收团款',
|
||
onSubmit: () => {
|
||
dialogState.messages.push({ type: 'alert', message: '您还没有登录或登录超时,请重新登陆!' });
|
||
},
|
||
});
|
||
|
||
await assert.rejects(
|
||
() => submitGuard.submitInfoFormAndConfirm(page, dialogState, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
}),
|
||
(error) => error.code === 'erp_login_required' && /test\.update/.test(error.message)
|
||
);
|
||
});
|
||
|
||
test('submitInfoFormAndConfirm rejects submit attempts without success evidence', async () => {
|
||
const dialogState = { messages: [] };
|
||
const page = fakePage({
|
||
bodyText: '修改团队 应收团款',
|
||
});
|
||
|
||
await assert.rejects(
|
||
() => submitGuard.submitInfoFormAndConfirm(page, dialogState, {
|
||
source: 'test.update',
|
||
waitMs: 0,
|
||
}),
|
||
(error) => error.code === 'erp_submit_unconfirmed' && /test\.update/.test(error.message)
|
||
);
|
||
});
|