63 行
4.3 KiB
JavaScript
63 行
4.3 KiB
JavaScript
// Run on the local contact preview with agent-browser eval. All requests are mocked.
|
|
(async function () {
|
|
if (!location.hostname.match(/^(127\.0\.0\.1|localhost)$/)) throw new Error('Use local preview only');
|
|
var form = document.querySelector('.ct-form');
|
|
var submit = form.querySelector('.ct-submit');
|
|
var status = form.querySelector('.ct-submit-status');
|
|
var originalFetch = window.fetch;
|
|
var calls = [];
|
|
var mode = 'reject';
|
|
var results = [];
|
|
function assert(condition, name) { if (!condition) throw new Error(name); results.push(name); }
|
|
window.fetch = async function (url, options) {
|
|
calls.push({url: String(url), method: options.method || 'GET', body: options.body || ''});
|
|
if (!options.method) {
|
|
if (mode === 'token-fail') throw new Error('network');
|
|
return {ok: true, json: async function () { return {code: 1, data: 'test-single-use-token'}; }};
|
|
}
|
|
if (mode === 'network-fail') throw new Error('network');
|
|
await new Promise(function (resolve) { setTimeout(resolve, 10); });
|
|
return {ok: true, json: async function () { return mode === 'success' ? {code: 1} : {code: 0, msg: '验证码不正确'}; }};
|
|
};
|
|
function fill() {
|
|
form.elements.title.value = '本地界面测试';
|
|
form.elements.name.value = '测试';
|
|
form.elements.phone.value = '0851-12345678';
|
|
form.elements.content.value = '本地模拟数据,不会向线上发送。';
|
|
if (form.elements.captcha) form.elements.captcha.value = 'test';
|
|
}
|
|
function send() { form.dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); }
|
|
async function settled() {
|
|
for (var i = 0; i < 100; i++) {
|
|
if (form.getAttribute('aria-busy') !== 'true') return;
|
|
await new Promise(function (resolve) { setTimeout(resolve, 5); });
|
|
}
|
|
throw new Error('Form did not settle');
|
|
}
|
|
try {
|
|
form.reset(); send();
|
|
assert(calls.length === 0 && document.activeElement === form.elements.title, 'Empty form: focus first error, no request');
|
|
form.querySelector('[data-topic]').click();
|
|
assert(form.elements.title.value === form.querySelector('[data-topic]').dataset.topic, 'Topic button fills title');
|
|
fill(); form.elements.phone.value = '123'; send();
|
|
assert(calls.length === 0 && form.elements.phone.getAttribute('aria-invalid') === 'true', 'Invalid phone blocked');
|
|
fill(); send(); send();
|
|
assert(submit.disabled, 'Submitting state disables button');
|
|
await settled();
|
|
assert(calls.filter(function (c) { return c.method === 'POST'; }).length === 1, 'Duplicate submit sends one POST');
|
|
var body = new URLSearchParams(calls.find(function (c) { return c.method === 'POST'; }).body);
|
|
assert(body.get('__token__') === 'test-single-use-token' && body.get('phone') === '0851-12345678', 'Uses fresh token and expected backend fields');
|
|
assert(status.dataset.state === 'error' && form.elements.content.value.length > 0 && !submit.disabled, 'Server rejection preserves fields and permits retry');
|
|
if (form.elements.captcha) assert(form.elements.captcha.value === '', 'Rejected submission refreshes captcha');
|
|
calls = []; fill(); mode = 'success'; send(); await settled();
|
|
assert(status.dataset.state === 'success' && form.elements.name.value === '' && form.elements.content.value === '', 'Confirmed success clears fields and announces result');
|
|
assert(calls.length === 2 && calls[0].method === 'GET', 'Retry obtains a new token');
|
|
calls = []; fill(); mode = 'network-fail'; send(); await settled();
|
|
assert(status.dataset.state === 'error' && status.textContent.includes('无法确认提交结果') && form.elements.content.value.length > 0, 'Unknown POST outcome preserves data without automatic retry');
|
|
assert(calls.length === 2 && !submit.disabled, 'Network failure releases button');
|
|
calls = []; fill(); mode = 'token-fail'; send(); await settled();
|
|
assert(calls.length === 1 && status.dataset.state === 'error', 'Token fetch failure never sends POST');
|
|
return {passed: results.length, checks: results, network: 'Mocked locally; no real messages sent'};
|
|
} finally { window.fetch = originalFetch; }
|
|
})();
|