Set the decision and its input
Actual CSS disables animation for prefers-reduced-motion. The faulty handler waits for animationend, leaving a supplied completed operation processing. The repair updates from the supplied operation promise. That result can be completed, failed or unknown.
| Case | Input JSON |
|---|---|
| Base test | {"motion":"reduce","outcome":"completed"} |
Run the supplied comparison
The browser applies both motion preferences and executes the handlers. Labels belong to the local synthetic operation; finishing an animation is not proof of an external business success.
| Path | Output JSON |
|---|---|
| Faulty path | {"state":"processing"} |
| Required path | {"state":"completed"} |
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(!['completed','failed','unknown'].includes(i.outcome)||!['normal','reduce'].includes(i.motion))return {held:true};
return withPage(async page=>{await page.setContent('<style>.animate{animation:pulse 10ms linear}@keyframes pulse{to{opacity:.5}}@media(prefers-reduced-motion:reduce){.animate{animation:none}}</style><div class="progress">Working</div><output id="state">processing</output>');
await page.evaluate(({corrected,outcome})=>{const state=document.querySelector('#state');if(corrected)Promise.resolve(outcome).then(result=>state.textContent=result);else document.querySelector('.progress').addEventListener('animationend',()=>state.textContent='completed');document.querySelector('.progress').classList.add('animate');},{corrected,outcome:i.outcome});
if(corrected||i.motion==='normal')await page.waitForFunction(()=>document.querySelector('#state').textContent!=='processing',{timeout:2000});
return {state:await page.locator('#state').textContent()};
},{reducedMotion:i.motion==='reduce'?'reduce':'no-preference'});
};
const cases=[{"input":{"motion":"reduce","outcome":"completed"},"corrected":false,"expected":{"state":"processing"}},{"input":{"motion":"reduce","outcome":"completed"},"corrected":true,"expected":{"state":"completed"}},{"input":{"motion":"normal","outcome":"completed"},"corrected":true,"expected":{"state":"completed"}},{"input":{"motion":"reduce","outcome":"failed"},"corrected":true,"expected":{"state":"failed"}},{"input":{"motion":"reduce","outcome":"unknown"},"corrected":true,"expected":{"state":"unknown"}}];
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
Normal motion reaches completed for a completed result. Failed and unknown results remain distinct under reduced motion.
- Apply the required motion preference
- Receive the operation result
- Update the labelled state
Do not convert a failed or unknown operation into a visual success.
| Condition | Input JSON | Expected output JSON |
|---|---|---|
| normal-motion operation | {"motion":"normal","outcome":"completed"} | {"state":"completed"} |
| failed actual result | {"motion":"reduce","outcome":"failed"} | {"state":"failed"} |
| unknown actual result | {"motion":"reduce","outcome":"unknown"} | {"state":"unknown"} |
What drives the repaired base completion?
Show the worked answer
The supplied operation result. Animationend may be absent; it cannot be the only completion signal.