commit d1ea8bad59ed5a23aace358832a1f3b6d5458d31
parent 43f2dcd05a9611902c75caff20f0a3adfb1f346f
Author: Botond Ballo <botond@mozilla.com>
Date: Tue, 9 Dec 2025 03:22:36 +0000
Bug 2003608 - Make PanZoomControllerTest#compositorScrollDelegateNotifiedOnRegistration more reliable. r=hiro,geckoview-reviewers
The original test approach required a way to reliably wait for a
composite to occur, but we didn't have a mechanism for that.
The new test approach works around it by using a second delegate
to test the "notified on registration" part, and the notification
of the first delegate as an indirect way of waiting for the composite.
Differential Revision: https://phabricator.services.mozilla.com/D275547
Diffstat:
1 file changed, 27 insertions(+), 43 deletions(-)
diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PanZoomControllerTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PanZoomControllerTest.kt
@@ -803,53 +803,37 @@ class PanZoomControllerTest : BaseSessionTest() {
// Load a simple vertically scrollable page
setupDocument(SIMPLE_SCROLL_TEST_PATH)
- // Without a CompositorScrollDelegate registered yet,
- // scroll down by 50 pixels, and wait for the change
- // to be propagated to the compositor.
- mainSession.evaluateJS("window.scrollTo(0, 50)")
- mainSession.promiseAllPaintsDone()
- mainSession.flushApzRepaints()
+ // Set up an initial CompositorScrollDelegate
+ // that appends updates to a local list
+ val updates: MutableList<ScrollPositionUpdate> = mutableListOf()
+ mainSession.setCompositorScrollDelegate(object : CompositorScrollDelegate {
+ override fun onScrollChanged(session: GeckoSession, update: ScrollPositionUpdate) {
+ updates.add(update)
+ }
+ })
- // The compositor reports a scroll position updates
- // delayed by one frame, so wait an additional frame
- // to ensure the y=50 gets reported.
- val promise = mainSession.evaluatePromiseJS(
- """
- new Promise(resolve => {
- window.requestAnimationFrame(() => resolve(true));
- });
- """,
- )
- assertThat(
- "we waited a frame",
- promise.value as Boolean,
- equalTo(true),
- )
- mainSession.promiseAllPaintsDone()
- mainSession.flushApzRepaints()
+ // Scroll to y=50 and wait for the initial delegate to
+ // be notified on this
+ mainSession.evaluateJS("window.scrollTo(0, 50)")
+ while (updates.size == 0 || updates[updates.size - 1].scrollY != 50.0f) {
+ mainSession.promiseAllPaintsDone()
+ mainSession.flushApzRepaints()
+ }
- // Register a CompositorScrollDelegate, and check that it
- // immediately gets notified about the scrollY=50, even
- // though that scroll offset was reached before the delegate
- // was registered.
+ // Register a second CompositorScrollDelegate, and check that it
+ // immediatley gets notified about the scrollY=50, even though
+ // that scroll offset was reached before the delegate was registered.
var wasNotified = false
- sessionRule.addExternalDelegateUntilTestEnd(
- GeckoSession.CompositorScrollDelegate::class,
- mainSession::setCompositorScrollDelegate,
- { mainSession.setCompositorScrollDelegate(null) },
- object : GeckoSession.CompositorScrollDelegate {
- override fun onScrollChanged(session: GeckoSession, update: ScrollPositionUpdate) {
- var scrollY = update.scrollY
- Log.d(logTag, "test scroll delegate onScrollChanged, scrollY = " + scrollY)
- wasNotified = true
- assertThat(
- "notified scrollY is correct",
- scrollY,
+ mainSession.setCompositorScrollDelegate(object : CompositorScrollDelegate {
+ override fun onScrollChanged(session: GeckoSession, update: ScrollPositionUpdate) {
+ wasNotified = true
+ assertThat(
+ "notified scrollY is correct",
+ update.scrollY,
equalTo(50.0f),
- )
- }
- },
- )
+ )
+ }
+ })
// setCompositorScrollDelegate() runs on the UI thread,
// so the delegate callback may not be called synchronously.