107 lines
5.7 KiB
JavaScript
107 lines
5.7 KiB
JavaScript
// Run with node tests/test_spot_application_validation.js [path/to/app.js].
|
||
// Uses only built-in modules and simulated DOM/fetch; never sends requests.
|
||
const assert = require('assert/strict');
|
||
const fs = require('fs');
|
||
const vm = require('vm');
|
||
const path = require('path');
|
||
const source = fs.readFileSync(process.argv[2] || path.join(__dirname, '../static/js/app.js'), 'utf8');
|
||
const code = source.slice(source.indexOf('function validateSpotApplicationForm('),
|
||
source.indexOf('function decideSpotApplication('));
|
||
|
||
function fixture() {
|
||
const nodes = {}, alerts = [], requests = [];
|
||
function node() {
|
||
return {value:'', style:{}, listeners:{}, disabled:false, error:'',
|
||
setCustomValidity(message) { this.error = message; },
|
||
addEventListener(name, fn) { this.listeners[name] = fn; },
|
||
remove() { this.removed = true; }};
|
||
}
|
||
const fields = {};
|
||
for (const name of ['product_name','barcode','sample_quantity','recipient_info','group_name','brand','department']) fields[name] = node();
|
||
const button = node(), form = node();
|
||
form.elements = {namedItem:name=>fields[name]};
|
||
form.querySelector = ()=>button;
|
||
form.checkValidity = ()=>['product_name','barcode','sample_quantity','recipient_info'].every(name=>
|
||
fields[name].value.trim() !== '' && !fields[name].error) &&
|
||
/^[0-9]{13}$/.test(fields.barcode.value) &&
|
||
/^\d+$/.test(fields.sample_quantity.value) && !fields.group_name.error;
|
||
form.reportValidity = ()=>{form.reported = true;};
|
||
nodes.spotApplicationForm = form;
|
||
const context = {
|
||
document: {getElementById:id=>nodes[id] || (nodes[id]=node()), createElement:node,
|
||
body:{appendChild:el=>{nodes[el.id]=el;}}},
|
||
window: {switchSpotApplicationTab:()=>{}}, alert:message=>alerts.push(message),
|
||
FormData:function(form) { this.form = form; },
|
||
fetch:(url, options)=>{
|
||
requests.push({url,options});
|
||
return Promise.resolve({json:()=>Promise.resolve(context.response)});
|
||
},
|
||
response:{code:409, msg:'无法保存,存在重复值:产品名称或条形码已存在'}
|
||
};
|
||
vm.createContext(context);
|
||
vm.runInContext(code, context);
|
||
context.openSpotApplicationModal();
|
||
function fill() {
|
||
fields.product_name.value='样品'; fields.barcode.value='0012345678901';
|
||
fields.sample_quantity.value='2'; fields.recipient_info.value='收件人及地址';
|
||
form.listeners.input.call(form);
|
||
}
|
||
const submit = ()=>form.listeners.submit.call(form,{preventDefault(){}});
|
||
return {context, fields, button, form, nodes, alerts, requests, fill, submit};
|
||
}
|
||
|
||
async function run() {
|
||
let f = fixture();
|
||
assert.equal(f.button.disabled, true);
|
||
const html = f.nodes.spotApplicationModal.innerHTML;
|
||
assert.equal((html.match(/(必填)/g)||[]).length, 5);
|
||
assert(!html.includes('>*</span>'));
|
||
for (const name of ['京东1组','京东2组','阿里1组','阿里2组','阿里3组']) assert(html.includes('value="'+name+'"'));
|
||
assert(html.includes('<select name="department">'));
|
||
assert(!html.includes('<option value="阿里">'));
|
||
f.submit(); assert.equal(f.requests.length, 0);
|
||
f.fill(); assert.equal(f.button.disabled, false);
|
||
f.fields.brand.value='洁维塔'; f.form.listeners.change.call(f.form);
|
||
assert.equal(f.button.disabled, true);
|
||
assert.equal(f.fields.group_name.required, true);
|
||
assert.equal(f.nodes.spotApplicationGroupRequired.style.display, '');
|
||
f.submit(); assert.equal(f.requests.length, 0);
|
||
f.fields.group_name.value='京东1组'; f.form.listeners.change.call(f.form);
|
||
assert.equal(f.button.disabled, false);
|
||
f.fields.group_name.value=''; f.fields.brand.value='泊紫汀兰';
|
||
f.form.listeners.change.call(f.form);
|
||
assert.equal(f.button.disabled, false);
|
||
assert.equal(f.fields.group_name.required, false);
|
||
assert.equal(f.fields.group_name.error, '');
|
||
assert.equal(f.nodes.spotApplicationGroupRequired.style.display, 'none');
|
||
for (const name of ['product_name','sample_quantity','barcode','recipient_info']) {
|
||
const original = f.fields[name].value;
|
||
f.fields[name].value=' '; f.form.listeners.input.call(f.form);
|
||
assert.equal(f.button.disabled, true, name);
|
||
f.fields[name].value=original; f.form.listeners.input.call(f.form);
|
||
assert.equal(f.button.disabled, false);
|
||
}
|
||
for (const value of ['123456789012','12345678901234','a123456789012','1234567890123']) {
|
||
f.fields.barcode.value=value; f.form.listeners.input.call(f.form);
|
||
assert.equal(f.button.disabled, true);
|
||
assert.equal(f.nodes.spotApplicationBarcodeError.style.display, 'block');
|
||
assert(f.fields.barcode.error.includes('请填写正确的条形码'));
|
||
f.submit(); assert.equal(f.requests.length, 0);
|
||
}
|
||
f.fill(); f.submit(); f.submit();
|
||
assert.equal(f.requests.length, 1, 'double-click must not send two requests');
|
||
assert.equal(f.button.disabled, true);
|
||
f.form.listeners.input.call(f.form);
|
||
assert.equal(f.button.disabled, true, 'editing during save must not enable button');
|
||
await new Promise(resolve=>setImmediate(resolve));
|
||
assert.equal(f.button.disabled, false);
|
||
assert(f.alerts[0].includes('存在重复值'));
|
||
assert(!f.nodes.spotApplicationModal.removed);
|
||
f = fixture(); f.fill(); f.context.response={code:0,id:8}; f.submit();
|
||
await new Promise(resolve=>setImmediate(resolve));
|
||
assert.equal(f.nodes.spotApplicationModal.removed, true);
|
||
assert.equal(f.alerts[0], '申请已添加');
|
||
console.log('PASS: required markers, disabled save, barcode validation, group options, duplicate errors, double submission, successful save');
|
||
}
|
||
run().catch(error=>{console.error(error);process.exitCode=1;});
|