Runs: Chrome 158.0.8110.0 (wpt@850b36a56, 2026-10-18) | Firefox 160.0a1 (wpt@b58866519, 2026-10-18) | Safari 254 preview (wpt@850b36a56, 2026-10-18) | Ladybird 1.0-1706f (wpt@850b36a56, 2026-10-18) | Servo Servo 0.7 (wpt@df642c414, 2026-10-17) | Blitz fb8d6c15e (wpt@cd1d8aa5b, 2026-10-17)
| Chrome | Firefox | Safari | Ladybird | Servo | Blitz | |
|---|---|---|---|---|---|---|
| Total | 1/1 | 1/1 | 1/1 | 0/1 | 0/1 | NOT RUN |
| Subtest | Chrome | Firefox | Safari | Ladybird | Servo | Blitz |
|---|---|---|---|---|---|---|
| mouse pointerevent attributes | PASS | PASS | PASS | FAIL | FAIL | — |
/pointerevents/pointerevent_movementxy.html
<!doctype html> <html> <head> <title>Pointer Events properties tests</title> <meta name="timeout" content="long"> <meta name="viewport" content="width=device-width"> <meta name="variant" content="?mouse"> <meta name="variant" content="?touch"> <meta name="variant" content="?pen"> <link rel="stylesheet" type="text/css" href="pointerevent_styles.css"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <!-- Additional helper script for common checks across event types --> <script type="text/javascript" src="pointerevent_support.js"></script> <style> #testContainer { touch-action: none; user-select: none; position: relative; } #box1 { top: 30px; left: 50px; background: black; } #box2 { top: 70px; left: 250px; background: red; } #innerFrame { top: 10px; left: 100px; } #square2 { visibility: block; } </style> <script> var inputSource = location.search.substring(1); var expectedPointerId = NaN; var lastScreenX = null; var lastScreenY = null; var lastEventDocument = null; var actionsPromise; function resetTestState() { lastScreenX = null; lastScreenY = null; lastEventDocument = null; } function loadFrame() { return new Promise(resolve => { const frame = document.getElementById('innerFrame'); frame.onload = resolve; frame.srcdoc = `<!doctype html> <meta name='viewport' content='width=device-width'>`; }); } var nonPointermoveEventList = [ "pointerover", "pointerenter", "pointerdown", "pointerup", "pointerout", "pointerleave", "gotpointercapture", "lostpointercapture"]; function injectInput(pointerType) { var pointerId = pointerType + "Pointer1"; return new test_driver.Actions() .addPointer(pointerId, pointerType) .pointerMove(0, 0, {origin: box1}) .pointerDown() // Moves in top frame (before iframe) .pointerMove(15, 20, {origin: box1}) .addTick() .pointerMove(30, 30, {origin: box1}) .addTick() // Move entering iframe .pointerMove(50, 40, {origin: box1}) .addTick() // Moves inside iframe .pointerMove(80, 30, {origin: box1}) .addTick() .pointerMove(110, 20, {origin: box1}) .addTick() // Move exiting iframe .pointerMove(0, 0, {origin: box2}) .addTick() // Moves in top frame (after iframe) .pointerMove(5, 5, {origin: box2}) .addTick() .pointerMove(-5, -5, {origin: box2}) .pointerUp() .send(); } async function run() { var test_pointerEvent = setup_pointerevent_test( "pointerevent attributes", [inputSource]); await loadFrame(); [ document, document.getElementById('innerFrame').contentDocument ].forEach(function(element) { nonPointermoveEventList.forEach(function(eventName) { on_event(element, eventName, function (event) { if (lastScreenX && lastScreenY) { test_pointerEvent.step(function() { assert_equals(event.movementX, 0, "movementX should be 0 for event other than pointermove."); assert_equals(event.movementY, 0, "movementY should be 0 for event other than pointermove."); }); } }); }); on_event(element, 'pointermove', function (event) { test_pointerEvent.step(function() { if (lastScreenX && lastScreenY && lastEventDocument === event.view.document) { assert_equals(event.movementX, event.screenX - lastScreenX, "movementX should be the delta between current event's and last event's screenX"); assert_equals(event.movementY, event.screenY - lastScreenY, "movementY should be the delta between current event's and last event's screenY"); } }); lastScreenX = event.screenX; lastScreenY = event.screenY; lastEventDocument = event.view.document; }); }); on_event(document.querySelector('#box1'), 'pointerdown', event => { event.target.releasePointerCapture(event.pointerId); test_pointerEvent.step(function() { assert_equals(event.pointerType, expectedPointerType, "Use the instructed pointer type."); }); lastScreenX = event.screenX; lastScreenY = event.screenY; lastEventDocument = event.view.document; }); on_event(document.querySelector('#box2'), 'pointerup', event => { // Make sure the test finishes after all the input actions. actionsPromise.then( () => { test_pointerEvent.done(); }); }); // Inject input actionsPromise = injectInput(inputSource); } </script> </head> <body onload="run()"> <h1>Pointer Events movementX/Y attribute test</h1> <h2 id="pointerTypeDescription"></h2> <h4> Test Description: This test checks the movementX/Y properties of pointer events. <ol> <li>Press down on the black square.</li> <li>Move your pointer slowly along a straight line to the red square.</li> <li>Release the pointer when you are over the red square.</li> </ol> Test passes if the proper behavior of the events is observed. </h4> <div id="testContainer"> <div id="box1" class="square"></div> <div id="box2" class="square"></div> <iframe id="innerFrame"></iframe> </div> <div class="spacer"></div> </body> </html>