Bug 1634575 [wpt PR 23350] - Use requestSkipAnimationFrame to avoid races in tests, a=testonly
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 13 May 2020 03:58:32 +0000
changeset 531024 564102394fc51865fcd91eb2c695ada3796e57f9
parent 531023 aaa4b8916c4687c0db21225ccaa15d607fdda80a
child 531025 73dfb76e1bf5808c55af973fe1f92df7c165e0a7
push id37435
push userapavel@mozilla.com
push dateWed, 20 May 2020 15:28:23 +0000
treeherdermozilla-central@5415da14ec9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1634575, 23350, 2173519, 26347
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1634575 [wpt PR 23350] - Use requestSkipAnimationFrame to avoid races in tests, a=testonly Automatic update from web-platform-tests Use requestSkipAnimationFrame to avoid races in tests (#23350) See https://github.com/immersive-web/webxr-test-api/issues/64 : the current usage is racy, tests should requestSkipAnimationFrame() after manipulating fakeDeviceController outside of the rAF loop. Would like to allow https://chromium-review.googlesource.com/c/chromium/src/+/2173519 to land and sync before landing this, to avoid manifest merge conflicts and further headaches for Alex :smile: fixes https://github.com/servo/servo/issues/26347 -- wpt-commits: a4d70f161fdb2e59e994e09fe142a880fb0b1d0e wpt-pr: 23350
testing/web-platform/tests/webxr/dom-overlay/ar_dom_overlay.https.html
testing/web-platform/tests/webxr/events_input_sources_change.https.html
testing/web-platform/tests/webxr/events_referenceSpace_reset_immersive.https.html
testing/web-platform/tests/webxr/events_session_select.https.html
testing/web-platform/tests/webxr/events_session_select_subframe.https.html
testing/web-platform/tests/webxr/events_session_squeeze.https.html
testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_disconnect.https.html
testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_input_registered.https.html
testing/web-platform/tests/webxr/getInputPose_handedness.https.html
testing/web-platform/tests/webxr/getInputPose_pointer.https.html
testing/web-platform/tests/webxr/getViewerPose_emulatedPosition.https.html
testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_inputSources.https.html
testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_transientInputSources.https.html
testing/web-platform/tests/webxr/resources/webxr_util.js
testing/web-platform/tests/webxr/xrBoundedReferenceSpace_updates.https.html
testing/web-platform/tests/webxr/xrInputSource_add_remove.https.html
testing/web-platform/tests/webxr/xrInputSource_emulatedPosition.https.html
testing/web-platform/tests/webxr/xrInputSource_profiles.https.html
testing/web-platform/tests/webxr/xrInputSource_sameObject.https.html
testing/web-platform/tests/webxr/xrPose_transform_sameObject.https.html
testing/web-platform/tests/webxr/xrReferenceSpace_originOffset.https.html
testing/web-platform/tests/webxr/xrReferenceSpace_originOffsetBounded.https.html
testing/web-platform/tests/webxr/xrSession_input_events_end.https.html
testing/web-platform/tests/webxr/xrSession_sameObject.https.html
testing/web-platform/tests/webxr/xrStationaryReferenceSpace_floorlevel_updates.https.html
--- a/testing/web-platform/tests/webxr/dom-overlay/ar_dom_overlay.https.html
+++ b/testing/web-platform/tests/webxr/dom-overlay/ar_dom_overlay.https.html
@@ -132,17 +132,17 @@ let testInput = function(overlayElement,
   let eventPromise = eventWatcher.wait_for(
     ["watcherstep", "select", "watcherdone"]);
 
   let input_source =
       fakeDeviceController.simulateInputSourceConnection(SCREEN_CONTROLLER);
   session.requestReferenceSpace('viewer').then(function(viewerSpace) {
     // Press the primary input button and then release it a short time later.
     debug('got viewerSpace');
-    session.requestAnimationFrame((time, xrFrame) => {
+    requestSkipAnimationFrame(session, (time, xrFrame) => {
       debug('got rAF 1');
       input_source.setOverlayPointerPosition(inner_a.offsetLeft + 1,
                                              inner_a.offsetTop + 1);
       input_source.startSelection();
 
       session.requestAnimationFrame((time, xrFrame) => {
         debug('got rAF 2');
         input_source.endSelection();
@@ -197,17 +197,17 @@ let testCrossOriginContent = function(ov
   // Use a "watcherstep" in between to verify this.
   let eventPromise = eventWatcher.wait_for(
     ["watcherstep", "select", "watcherdone"]);
 
   let input_source =
       fakeDeviceController.simulateInputSourceConnection(SCREEN_CONTROLLER);
   session.requestReferenceSpace('viewer').then(function(viewerSpace) {
     // Press the primary input button and then release it a short time later.
-    session.requestAnimationFrame((time, xrFrame) => {
+    requestSkipAnimationFrame(session, (time, xrFrame) => {
       debug('got rAF 1');
       input_source.setOverlayPointerPosition(iframe.offsetLeft + 1,
                                              iframe.offsetTop + 1);
       input_source.startSelection();
 
       session.requestAnimationFrame((time, xrFrame) => {
         debug('got rAF 2');
         input_source.endSelection();
--- a/testing/web-platform/tests/webxr/events_input_sources_change.https.html
+++ b/testing/web-platform/tests/webxr/events_input_sources_change.https.html
@@ -96,17 +96,17 @@ let testFunction = function(session, fak
     targetRayMode: "tracked-pointer",
     pointerOrigin: VALID_POINTER_TRANSFORM,
     profiles: [],
     selectionClicked: true
   });
 
   // Make our input source disappear after one frame, and wait an additional
   // frame for that disappearance to propogate.
-  session.requestAnimationFrame((time, xrFrame) => {
+  requestSkipAnimationFrame(session, (time, xrFrame) => {
     input_source.disconnect();
     session.requestAnimationFrame((time, xrFrame) => {});
   });
 
   return eventPromise;
 };
 
 xr_session_promise_test(
--- a/testing/web-platform/tests/webxr/events_referenceSpace_reset_immersive.https.html
+++ b/testing/web-platform/tests/webxr/events_referenceSpace_reset_immersive.https.html
@@ -35,17 +35,17 @@ let testFunction = function(session, fak
       refSpace.dispatchEvent(watcherDone);
     }, false);
     return eventWatcher.wait_for(["reset", "watcherdone"]);
   });
 
   fakeDeviceController.simulateResetPose();
 
   // The triggered resetPose event should arrive after the next Animation Frame
-  session.requestAnimationFrame(() => {});
+  requestSkipAnimationFrame(session, () => {});
 
   return resetPromise;
 };
 
 xr_session_promise_test(
   immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr');
 
 </script>
--- a/testing/web-platform/tests/webxr/events_session_select.https.html
+++ b/testing/web-platform/tests/webxr/events_session_select.https.html
@@ -87,17 +87,17 @@ let testFunction = function(session, fak
 
   session.requestReferenceSpace('viewer').then(function(viewerSpace) {
     xrViewerSpace = viewerSpace;
 
     session.requestReferenceSpace('local').then((referenceSpace) => {
       currentReferenceSpace = referenceSpace;
 
       // Press the primary input button and then release it a short time later.
-      session.requestAnimationFrame((time, xrFrame) => {
+      requestSkipAnimationFrame(session, (time, xrFrame) => {
         input_source.startSelection();
 
           session.requestAnimationFrame((time, xrFrame) => {
             input_source.endSelection();
 
             session.requestAnimationFrame((time, xrFrame) => {
               // Need to process one more frame to allow select to propegate.
             });
--- a/testing/web-platform/tests/webxr/events_session_select_subframe.https.html
+++ b/testing/web-platform/tests/webxr/events_session_select_subframe.https.html
@@ -46,17 +46,17 @@ let testFunction = function(session, fak
   }
   session.addEventListener("selectstart", onSessionSelectStart, false);
   session.addEventListener("selectend", onSessionSelectEnd, false);
   session.addEventListener("select", onSessionSelect, false);
 
   let input_source = fakeDeviceController.simulateInputSourceConnection(VALID_CONTROLLER);
 
   // Press the primary input button and then release it a short time later.
-  session.requestAnimationFrame((time, xrFrame) => {
+  requestSkipAnimationFrame(session, (time, xrFrame) => {
     input_source.simulateSelect();
 
     session.requestAnimationFrame((time, xrFrame) => {
       // Need to process one more frame to allow select to propegate.
     });
   });
 };
 
--- a/testing/web-platform/tests/webxr/events_session_squeeze.https.html
+++ b/testing/web-platform/tests/webxr/events_session_squeeze.https.html
@@ -109,17 +109,17 @@ let testFunction = function(session, fak
 
   session.requestReferenceSpace('viewer').then(function(viewerSpace) {
     xrViewerSpace = viewerSpace;
 
     session.requestReferenceSpace('local').then((referenceSpace) => {
       currentReferenceSpace = referenceSpace;
 
       //Simulate a grip starting then release it a short time later.
-      session.requestAnimationFrame((time, xrFrame) => {
+      requestSkipAnimationFrame(session, (time, xrFrame) => {
         input_source.updateButtonState(pressed_grip_button);
 
           session.requestAnimationFrame((time, xrFrame) => {
             input_source.updateButtonState(unpressed_grip_button);
 
             session.requestAnimationFrame((time, xrFrame) => {
               // Need to process one more frame to allow grip to propegate.
             });
--- a/testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_disconnect.https.html
+++ b/testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_disconnect.https.html
@@ -127,17 +127,17 @@ let testFunction = function(session, fak
   // a rAF after each step:
   // 1. Disconnect the gamepad (so we can verify that the gamepad is disconnected)
   // 2. Reconnect the gamepad (so we can set up to disconnect the controller)
   // 3. Disconnect the controller (so we can verify that it's gamepad gets disconnected).
   // 4. Adds the controller back (so we can test the end Session)
   // 5. Waits for all of the input events to finish propagating, then ends the
   // session, at which point the controller should be disconnected.
   return new Promise((resolve) => {
-    session.requestAnimationFrame(() => {
+    requestSkipAnimationFrame(session, () => {
       input_source.setSupportedButtons([]);
       session.requestAnimationFrame(() => {
         input_source.setSupportedButtons(gamepadButtons);
         session.requestAnimationFrame(() => {
           input_source.disconnect();
           session.requestAnimationFrame(() => {
             input_source.reconnect();
             session.requestAnimationFrame(() => {
--- a/testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_input_registered.https.html
+++ b/testing/web-platform/tests/webxr/gamepads-module/xrInputSource_gamepad_input_registered.https.html
@@ -64,17 +64,17 @@ let testFunction = function(session, fak
   // each step):
   // 1) Press the mock gamepad's button (so we can verify the button press makes
   //    its way to the WebXR gamepad and that it does not fire an
   //    inputsourceschange event).
   // 2) Update the mock gamepad's input axes values (so we can verify the
   //    updated values make their way to the WebXR gamepad and that it does not
   //    fire an inputsourceschange event).
   return new Promise((resolve) => {
-    session.requestAnimationFrame(() => {
+    requestSkipAnimationFrame(session, () => {
       // Make sure the exposed gamepad has the number of buttons and axes we
       // requested.
       // 3 Buttons: trigger, grip, touchpad
       // 2 Axes from the touchpad
       cached_input_source = session.inputSources[0];
       cached_gamepad = cached_input_source.gamepad;
       t.step(() => {
         assert_equals(cached_gamepad.index, -1);
--- a/testing/web-platform/tests/webxr/getInputPose_handedness.https.html
+++ b/testing/web-platform/tests/webxr/getInputPose_handedness.https.html
@@ -70,15 +70,15 @@ let testFunction =
         // Handedness was set to "none" again, make sure it propegates.
         assert_equals(source.handedness, "none");
       });
 
       resolve();
     }
 
     // Handedness only updates during an XR frame.
-    session.requestAnimationFrame(CheckNone);
+    requestSkipAnimationFrame(session, CheckNone);
   });
 
 xr_session_promise_test(
   testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
 
 </script>
--- a/testing/web-platform/tests/webxr/getInputPose_pointer.https.html
+++ b/testing/web-platform/tests/webxr/getInputPose_pointer.https.html
@@ -82,16 +82,16 @@ let testFunction =
             VALID_POINTER, FLOAT_EPSILON,
             "Pointer matrix not set properly.");
         });
 
         resolve();
       }
 
       // Can only request input poses in an xr frame.
-      session.requestAnimationFrame(CheckInvalidGrip);
+      requestSkipAnimationFrame(session, CheckInvalidGrip);
     });
   });
 
 xr_session_promise_test(
   testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
 
 </script>
--- a/testing/web-platform/tests/webxr/getViewerPose_emulatedPosition.https.html
+++ b/testing/web-platform/tests/webxr/getViewerPose_emulatedPosition.https.html
@@ -40,17 +40,17 @@
               assert_equals(pose.emulatedPosition, true);
             });
 
             // Finished.
             debug('resolve');
             resolve();
           }
 
-          session.requestAnimationFrame(CheckPositionNotEmulated);
+          requestSkipAnimationFrame(session, CheckPositionNotEmulated);
         }));
     };
 
     xr_session_promise_test(testName, testFunction,
       TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
 
   </script>
 </body>
--- a/testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_inputSources.https.html
+++ b/testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_inputSources.https.html
@@ -50,17 +50,17 @@ const fakeDeviceInitParams = {
 // |nextFrameExpectedPoses| - array of expected pose objects. The poses should be expressed in local space.
 //                            Null entries in the array mean that the given entry will not be validated.
 let testFunctionGenerator = function(ray, expectedPoses, inputFromPointer, nextFrameExpectedPoses) {
   const testFunction = function(session, fakeDeviceController, t) {
     return session.requestReferenceSpace('local').then((localRefSpace) => new Promise((resolve, reject) => {
 
       const input_source_controller = fakeDeviceController.simulateInputSourceConnection(screen_controller_init);
 
-      session.requestAnimationFrame((time, frame) => {
+      requestSkipAnimationFrame(session, (time, frame) => {
         t.step(() => {
           assert_equals(session.inputSources.length, 1);
         });
 
         const input_source = session.inputSources[0];
         const hitTestOptionsInit = {
           space: input_source.targetRaySpace,
           offsetRay: ray,
--- a/testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_transientInputSources.https.html
+++ b/testing/web-platform/tests/webxr/hit-test/ar_hittest_subscription_transientInputSources.https.html
@@ -51,17 +51,17 @@ const fakeDeviceInitParams = {
 //                            Null entries in the array mean that the given entry will not be validated.
 let testFunctionGenerator = function(ray, expectedPoses, inputFromPointer, nextFrameExpectedPoses) {
   const testFunction = function(session, fakeDeviceController, t) {
     let debug = xr_debug.bind(this, 'testFunction');
     return session.requestReferenceSpace('local').then((localRefSpace) => new Promise((resolve, reject) => {
 
       const input_source_controller = fakeDeviceController.simulateInputSourceConnection(screen_controller_init);
 
-      session.requestAnimationFrame((time, frame) => {
+      requestSkipAnimationFrame(session, (time, frame) => {
         debug('rAF 1');
         t.step(() => {
           assert_equals(session.inputSources.length, 1);
         });
 
         const hitTestOptionsInit = {
           profile: "generic-touchscreen",
           offsetRay: ray,
--- a/testing/web-platform/tests/webxr/resources/webxr_util.js
+++ b/testing/web-platform/tests/webxr/resources/webxr_util.js
@@ -39,16 +39,28 @@ function xr_promise_test(name, func, pro
       await navigator.xr.test.disconnectAllDevices();
     });
 
     xr_debug(name, 'main');
     return func(t);
   }, name, properties);
 }
 
+// A utility function for waiting one animation frame before running the callback
+//
+// This is only needed after calling FakeXRDevice methods outside of an animation frame
+//
+// This is so that we can paper over the potential race allowed by the "next animation frame"
+// concept https://immersive-web.github.io/webxr-test-api/#xrsession-next-animation-frame
+function requestSkipAnimationFrame(session, callback) {
+ session.requestAnimationFrame(() => {
+  session.requestAnimationFrame(callback);
+ });
+}
+
 // A test function which runs through the common steps of requesting a session.
 // Calls the passed in test function with the session, the controller for the
 // device, and the test object.
 // Requires a webglCanvas on the page.
 function xr_session_promise_test(
     name, func, fakeDeviceInit, sessionMode, sessionInit, properties, glcontextPropertiesParam, gllayerPropertiesParam) {
   let testDeviceController;
   let testSession;
--- a/testing/web-platform/tests/webxr/xrBoundedReferenceSpace_updates.https.html
+++ b/testing/web-platform/tests/webxr/xrBoundedReferenceSpace_updates.https.html
@@ -44,16 +44,16 @@ let testFunction = function(session, fak
               }
             });
 
             resolve();
           }
 
           // Now set the bounds explicitly and check again on the next frame.
           fakeDeviceController.setBoundsGeometry(VALID_BOUNDS);
-          session.requestAnimationFrame(onFrame);
+          requestSkipAnimationFrame(session, onFrame);
         });
     });
 };
 
 xr_session_promise_test(testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { 'requiredFeatures': ['bounded-floor'] });
 
 </script>
--- a/testing/web-platform/tests/webxr/xrInputSource_add_remove.https.html
+++ b/testing/web-platform/tests/webxr/xrInputSource_add_remove.https.html
@@ -16,17 +16,17 @@ let testFunction = (session, fakeDeviceC
     let input_sources = session.inputSources;
 
     t.step( () => {
       assert_equals(input_sources.length, 0);
     });
 
     let input_source_1 = fakeDeviceController.simulateInputSourceConnection(RIGHT_CONTROLLER);
 
-    session.requestAnimationFrame((time, xrFrame) => {
+    requestSkipAnimationFrame(session, (time, xrFrame) => {
       let input_sources = session.inputSources;
 
       t.step( () => {
         assert_equals(input_sources.length, 1);
         assert_equals(input_sources[0].targetRayMode, "tracked-pointer");
         assert_equals(input_sources[0].handedness, "right");
       });
 
--- a/testing/web-platform/tests/webxr/xrInputSource_emulatedPosition.https.html
+++ b/testing/web-platform/tests/webxr/xrInputSource_emulatedPosition.https.html
@@ -48,16 +48,16 @@ let testFunction =
           assert_not_equals(grip_pose, null);
           assert_equals(grip_pose.emulatedPosition, true);
         });
 
         resolve();
       }
 
       // Can only request input poses in an xr frame.
-      session.requestAnimationFrame(CheckPositionNotEmulated);
+      requestSkipAnimationFrame(session, CheckPositionNotEmulated);
     });
   });
 
 xr_session_promise_test(
   testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
 
 </script>
--- a/testing/web-platform/tests/webxr/xrInputSource_profiles.https.html
+++ b/testing/web-platform/tests/webxr/xrInputSource_profiles.https.html
@@ -17,17 +17,17 @@ let testFunction = function(session, fak
     targetRayMode: "tracked-pointer",
     pointerOrigin: VALID_POINTER_TRANSFORM,
     profiles: ["most-specific-name", "less-specific-name"]
   });
 
   // Input events and state changes need one frame to propagate, which is why we
   // are requesting an animation frame before checking the profiles list.
   return new Promise((resolve) => {
-    session.requestAnimationFrame(() => {
+    requestSkipAnimationFrame(session, () => {
       let profiles = session.inputSources[0].profiles;
       t.step(() => {
         assert_equals(profiles.length, 2);
         assert_equals(profiles[0], "most-specific-name");
         assert_equals(profiles[1], "less-specific-name");
       }, "Verify profiles list is set");
       resolve();
     });
--- a/testing/web-platform/tests/webxr/xrInputSource_sameObject.https.html
+++ b/testing/web-platform/tests/webxr/xrInputSource_sameObject.https.html
@@ -13,17 +13,17 @@ let testFunction = function(session, fak
     let input_source = fakeDeviceController.simulateInputSourceConnection({
       handedness: "right",
       targetRayMode: "tracked-pointer",
       pointerOrigin: VALID_POINTER_TRANSFORM,
       gripOrigin: VALID_GRIP_TRANSFORM,
       profiles: ["foo", "bar"]
     });
 
-    session.requestAnimationFrame((time, xrFrame) => {
+    requestSkipAnimationFrame(session, (time, xrFrame) => {
       let source = session.inputSources[0];
       let targetRaySpace = source.targetRaySpace;
       let gripSpace = source.gripSpace;
       let profiles = source.profiles;
 
       t.step(() => {
         assert_not_equals(targetRaySpace, null,
           "target ray space must not be null");
--- a/testing/web-platform/tests/webxr/xrPose_transform_sameObject.https.html
+++ b/testing/web-platform/tests/webxr/xrPose_transform_sameObject.https.html
@@ -14,17 +14,17 @@ let testFunction = function(session, fak
       handedness: "right",
       targetRayMode: "tracked-pointer",
       pointerOrigin: VALID_POINTER_TRANSFORM,
       gripOrigin: VALID_GRIP_TRANSFORM,
       profiles: []
     });
 
     session.requestReferenceSpace('local').then((referenceSpace) => {
-      session.requestAnimationFrame((time, xrFrame) => {
+      requestSkipAnimationFrame(session, (time, xrFrame) => {
         let source = session.inputSources[0];
         let input_pose = xrFrame.getPose(source.targetRaySpace, referenceSpace);
 
         // Make sure that the transform attribute is the same object each time
         // we access it. This verifies that the XRPose does *not* do something
         // spec-noncompliant such as creating and returning a new
         // XRRigidTransform object each time the attribute is accessed.
         let transform = input_pose.transform;
--- a/testing/web-platform/tests/webxr/xrReferenceSpace_originOffset.https.html
+++ b/testing/web-platform/tests/webxr/xrReferenceSpace_originOffset.https.html
@@ -121,16 +121,16 @@ let testFunction =
 
         referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform(new_position2, new_orientation2));
         CheckState(referenceSpace, EXPECTED_VIEW_MATRIX_3, EXPECTED_GRIP_MATRIX_3, EXPECTED_RAY_MATRIX_3, "Second transform");
 
         resolve();
       }
 
       // Can only request input poses in an xr frame.
-      session.requestAnimationFrame(OnFrame);
+      requestSkipAnimationFrame(session, OnFrame);
     });
   });
 
 xr_session_promise_test(
   testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
 
 </script>
--- a/testing/web-platform/tests/webxr/xrReferenceSpace_originOffsetBounded.https.html
+++ b/testing/web-platform/tests/webxr/xrReferenceSpace_originOffsetBounded.https.html
@@ -62,17 +62,17 @@ function testFunction(session, fakeDevic
     handedness: "right",
     targetRayMode: "tracked-pointer",
     pointerOrigin: LOCAL_POINTER_TRANSFORM,
     gripOrigin: INITIAL_GRIP_TRANSFORM,
     profiles: []
   });
 
   return new Promise((resolve, reject) => {
-    session.requestAnimationFrame((time, frame) => {
+    requestSkipAnimationFrame(session, (time, frame) => {
       let input_source = session.inputSources[0];
 
       session.requestReferenceSpace('bounded-floor').then((referenceSpace) => {
 
         function CheckState(
           reference_space,
           expected_view_matrix,
           expected_grip_matrix,
--- a/testing/web-platform/tests/webxr/xrSession_input_events_end.https.html
+++ b/testing/web-platform/tests/webxr/xrSession_input_events_end.https.html
@@ -37,17 +37,17 @@ let testFunction = function(session, fak
   function sendClick(session) {
     let input_source = fakeDeviceController.simulateInputSourceConnection({
       handedness: "right",
       targetRayMode: "tracked-pointer",
       pointerOrigin: VALID_POINTER_TRANSFORM,
       profiles: [],
       selectionClicked: true
     });
-    session.requestAnimationFrame(() => {});
+    requestSkipAnimationFrame(session, () => {});
   }
 
   function sessionEndTest(endEvent, eventOrder) {
     return requestImmersiveSession().then((session) => {
       let eventWatcher = new EventWatcher(t, session,
         ["inputsourceschange", "selectstart", "select", "selectend", "end"]);
       let eventPromise = eventWatcher.wait_for(eventOrder);
 
--- a/testing/web-platform/tests/webxr/xrSession_sameObject.https.html
+++ b/testing/web-platform/tests/webxr/xrSession_sameObject.https.html
@@ -13,17 +13,17 @@ let testFunction = function(session, fak
     let input_source = fakeDeviceController.simulateInputSourceConnection({
       handedness: "right",
       targetRayMode: "tracked-pointer",
       pointerOrigin: VALID_POINTER_TRANSFORM,
       gripOrigin: VALID_GRIP_TRANSFORM,
       profiles: ["foo", "bar"]
     });
 
-    session.requestAnimationFrame((time, xrFrame) => {
+    requestSkipAnimationFrame(session, (time, xrFrame) => {
       let renderState = session.renderState;
       let sources = session.inputSources;
 
       t.step(() => {
         assert_not_equals(renderState, null, "renderState must not be null.");
         assert_not_equals(sources, null, "inputSources must not be null.");
 
         // Make sure [SameObject] attributes actually have the same object
--- a/testing/web-platform/tests/webxr/xrStationaryReferenceSpace_floorlevel_updates.https.html
+++ b/testing/web-platform/tests/webxr/xrStationaryReferenceSpace_floorlevel_updates.https.html
@@ -31,19 +31,17 @@ let testFunction = function(session, fak
           assert_approx_equals(poseMatrix[12], 0.0, FLOAT_EPSILON);
           assert_greater_than(poseMatrix[13], 1.0);
           assert_approx_equals(poseMatrix[14], 0.0, FLOAT_EPSILON);
 
           fakeDeviceController.setFloorOrigin(VALID_FLOOR_ORIGIN);
 
           // Need to request one animation frame for the new stage transform to
           // propagate before we check that it's what we expect.
-          session.requestAnimationFrame(() => {
-            session.requestAnimationFrame(onFrame);
-          });
+          requestSkipAnimationFrame(session, onFrame);
         });
       }
 
       function onFrame(time, xrFrame) {
         t.step( () => {
           // Check that stage transform was updated.
           let pose = xrFrame.getViewerPose(referenceSpace);
           assert_not_equals(pose, null);
@@ -53,18 +51,16 @@ let testFunction = function(session, fak
         });
 
         // Finished.
         resolve();
       }
 
       // Need to wait one frame for the removal to propagate before we check that
       // everything is at the expected emulated position.
-      session.requestAnimationFrame(() => {
-        session.requestAnimationFrame(onFirstFrame);
-      });
+      requestSkipAnimationFrame(session, onFirstFrame);
     }));
 };
 
 xr_session_promise_test(immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr', { 'requiredFeatures': ['local-floor'] });
 xr_session_promise_test(nonImmersiveTestName, testFunction, fakeDeviceInitParams, 'inline', { 'requiredFeatures': ['local-floor'] });
 
 </script>