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) ); });