Set the decision and its input
The synthetic form contains Quantity text5 and an empty Code field. Explicit scan-capture mode must route A12 to Code while Quantity remains focused. A faulty listener appends to the focused field, producing5A12. Mode is a supplied choice, not a timing-based hardware classification.
| Case | Input JSON |
|---|---|
| Base test | {"capture":true,"keys":["A","1","2","Enter"]} |
Run the supplied comparison
The example dispatches actual DOM key events and inspects both controls. It proves this routing behaviour, not scanner-driver certification or numeric acceptance of Quantity.
| Path | Output JSON |
|---|---|
| Faulty path | {"quantity":"5A12","code":""} |
| Required path | {"quantity":"5","code":"A12"} |
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
const htmlEscape=s=>String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
async function withPage(action,options={}){
const require=createRequire(import.meta.url);const {chromium}=require('playwright');
const browser=await chromium.launch({headless:true});
try{const context=await browser.newContext(options);const page=await context.newPage();
const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
return await action(page,context,requests);
}finally{await browser.close();}
}
const run=async function run(i,corrected=true){
if(typeof i.capture!=='boolean')return {held:true};
return withPage(async page=>{await page.setContent('<label>Quantity<input id="quantity" value="5"></label><label>Code<input id="code"></label>');
await page.evaluate(({corrected,capture})=>{document.addEventListener('keydown',e=>{if(e.key==='Enter')return;const target=corrected&&capture?document.querySelector('#code'):document.activeElement;target.value+=e.key;});},{corrected,capture:i.capture});
await page.focus('#quantity');for(const key of i.keys)await page.dispatchEvent('#quantity','keydown',{key});
return page.evaluate(()=>({quantity:document.querySelector('#quantity').value,code:document.querySelector('#code').value}));});
};
const cases=[{"input":{"capture":true,"keys":["A","1","2","Enter"]},"corrected":false,"expected":{"quantity":"5A12","code":""}},{"input":{"capture":true,"keys":["A","1","2","Enter"]},"corrected":true,"expected":{"quantity":"5","code":"A12"}},{"input":{"capture":false,"keys":["A"]},"corrected":true,"expected":{"quantity":"5A","code":""}},{"input":{"capture":true,"keys":[]},"corrected":true,"expected":{"quantity":"5","code":""}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
Choose from the boundary evidence
Manual mode follows the focused text field and can produce5A, which still needs quantity validation. An empty scan changes neither control.
- Select capture mode
- Send the focused-field events
- Inspect both final values
Ordinary editing still needs the field’s own validation.
| Condition | Input JSON | Expected output JSON |
|---|---|---|
| manual input mode | {"capture":false,"keys":["A"]} | {"quantity":"5A","code":""} |
| empty scan sequence | {"capture":true,"keys":[]} | {"quantity":"5","code":""} |
What values are required after the base capture?
Show the worked answer
Quantity remains5 and Code becomes A12. A capture instruction does not authorise replacing another field.