Skip to content
Permalink
Browse files
Tests under pointerevents/ios are flaky
https://bugs.webkit.org/show_bug.cgi?id=197624

Reviewed by Dean Jackson.

Tests under pointerevents/ios generate touches that use UIScriptController may not succeed if ran in multiple iterations or in a specific
order due to not ensuring that all touches are released when the test completes. We now ensure that we do when running swipes, taps, and pinches.

* pointerevents/ios/pointer-events-dispatch-on-stylus.html: Use the new ui.tapStylus() method to generate a tap with the stylus which ensures all
touches are removed upon completion.
* pointerevents/ios/pointer-events-dispatch-on-touch.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-release-exception.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-release.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-prevent-default-allows-click-event.html: Ensure both the "click" event and the tap generation have succeeded before
marking the test as complete.
* pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/touch-action-none-link-traversal.html: Ensure both the "load" event and the tap generation have succeeded before marking the test
as complete.
* pointerevents/ios/touch-action-pan-x-pan-y.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pan-x.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pan-y.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Remove the requestAnimationFrame() call since ui.pinchOut() now resolves its promise
once all touches have completed.
* pointerevents/ios/touch-action-pointercancel-pan-x.html: We don't need to track "pointermove" events since dispatch of "pointercancel" is asynchronous
and the number of "pointermove" events prior to its dispatch can legitimately vary.
* pointerevents/ios/touch-action-pointercancel-pan-y.html: We don't need to track "pointermove" events since dispatch of "pointercancel" is asynchronous
and the number of "pointermove" events prior to its dispatch can legitimately vary.
* pointerevents/utils.js:
(const.ui.new.UIController.prototype.swipe): Wait until the swipe is complete before resolving the promise.
(const.ui.new.UIController.prototype.pinchOut): Use a custom sequence to ensure that the pinch releases touches upon completion.
(const.ui.new.UIController.prototype.tapStylus): Introduce this new method to perform a stylus tap which ensures all touches are complete before resolving
the promise.
(const.ui.new.UIController.prototype.beginTouches): Deleted.
(const.ui.new.UIController.prototype.beginStylus): Deleted.

Canonical link: https://commits.webkit.org/211759@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244974 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
graouts committed May 6, 2019
1 parent 047bf85 commit f2af8e18df282e3872d3a76ea8ecdc7d97d4471a
Show file tree
Hide file tree
Showing 16 changed files with 101 additions and 97 deletions.
@@ -1,3 +1,44 @@
2019-05-06 Antoine Quint <graouts@apple.com>

Tests under pointerevents/ios are flaky
https://bugs.webkit.org/show_bug.cgi?id=197624

Reviewed by Dean Jackson.

Tests under pointerevents/ios generate touches that use UIScriptController may not succeed if ran in multiple iterations or in a specific
order due to not ensuring that all touches are released when the test completes. We now ensure that we do when running swipes, taps, and pinches.

* pointerevents/ios/pointer-events-dispatch-on-stylus.html: Use the new ui.tapStylus() method to generate a tap with the stylus which ensures all
touches are removed upon completion.
* pointerevents/ios/pointer-events-dispatch-on-touch.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-release-exception.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-implicit-capture-release.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/pointer-events-prevent-default-allows-click-event.html: Ensure both the "click" event and the tap generation have succeeded before
marking the test as complete.
* pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html: Use a tap to ensure all touches are removed upon completion.
* pointerevents/ios/touch-action-none-link-traversal.html: Ensure both the "load" event and the tap generation have succeeded before marking the test
as complete.
* pointerevents/ios/touch-action-pan-x-pan-y.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pan-x.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pan-y.html: Remove the requestAnimationFrame() call since ui.swipe() now resolves its promise once all touches
have completed.
* pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Remove the requestAnimationFrame() call since ui.pinchOut() now resolves its promise
once all touches have completed.
* pointerevents/ios/touch-action-pointercancel-pan-x.html: We don't need to track "pointermove" events since dispatch of "pointercancel" is asynchronous
and the number of "pointermove" events prior to its dispatch can legitimately vary.
* pointerevents/ios/touch-action-pointercancel-pan-y.html: We don't need to track "pointermove" events since dispatch of "pointercancel" is asynchronous
and the number of "pointermove" events prior to its dispatch can legitimately vary.
* pointerevents/utils.js:
(const.ui.new.UIController.prototype.swipe): Wait until the swipe is complete before resolving the promise.
(const.ui.new.UIController.prototype.pinchOut): Use a custom sequence to ensure that the pinch releases touches upon completion.
(const.ui.new.UIController.prototype.tapStylus): Introduce this new method to perform a stylus tap which ensures all touches are complete before resolving
the promise.
(const.ui.new.UIController.prototype.beginTouches): Deleted.
(const.ui.new.UIController.prototype.beginStylus): Deleted.

2019-05-06 Truitt Savell <tsavell@apple.com>

Fix typo in https://trac.webkit.org/changeset/244962/webkit
@@ -27,7 +27,7 @@
assert_approx_equals(event.tiltY, 20, 1);
test.done();
});
ui.beginStylus({ x: 50, y: 50, pressure: 0.75, azimuthAngle: fifteenDegrees, altitudeAngle: thirtyDegrees });
ui.tapStylus({ x: 50, y: 50, pressure: 0.75, azimuthAngle: fifteenDegrees, altitudeAngle: thirtyDegrees });
}, "Pointer events get dispatched in response to a stylus.");

</script>
@@ -21,7 +21,7 @@
assert_equals(event.pointerType, "touch");
test.done();
});
ui.beginTouches({ x: 50, y: 50 });
ui.tap({ x: 50, y: 50 });
}, "Pointer events get dispatched in response to a touch.");

</script>
@@ -14,7 +14,7 @@

target_test((target, test) => {
target.addEventListener("pointerdown", event => assert_true(target.hasPointerCapture(event.pointerId)));
ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
ui.tap({ x: 50, y: 50 }).then(() => test.done());
}, "Calling hasPointerCapture() in the 'pointerdown' event handler returns true for direct manipulation devices.");

</script>
@@ -18,7 +18,7 @@
assert_throws("NotFoundError", () => target.releasePointerCapture(event.pointerId + 1));
assert_true(target.hasPointerCapture(event.pointerId));
});
ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
ui.tap({ x: 50, y: 50 }).then(() => test.done());
}, "Calling releasePointerCapture() in the 'pointerdown' event handler with a bogus pointer id raises an exception and does not alter pointer capture.");

</script>
@@ -18,7 +18,7 @@
target.releasePointerCapture(event.pointerId);
assert_false(target.hasPointerCapture(event.pointerId));
});
ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
ui.tap({ x: 50, y: 50 }).then(() => test.done());
}, "Calling releasePointerCapture() in the 'pointerdown' event handler makes hasPointerCapture() return false.");

</script>
@@ -14,8 +14,9 @@

target_test((target, test) => {
target.addEventListener("pointerdown", event => event.preventDefault());
target.addEventListener("click", event => test.done());
ui.tap({ x: 100, y: 100 });
const clicked = new Promise(resolve => target.addEventListener("click", resolve));
const tapped = ui.tap({ x: 100, y: 100 });
Promise.all([clicked, tapped]).then(() => test.done());
}, "A 'click' event is dispatched when tapping even if preventDefault() was called for a pointer event.");

</script>
@@ -19,7 +19,7 @@
assert_true(target.hasPointerCapture(event.pointerId));
assert_throws("InvalidStateError", () => document.createElement("div").setPointerCapture(event.pointerId), "Calling setPointerCapture() with a valid pointer id on a disconnected element throws an InvalidStateError exception.");
});
ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
ui.tap({ x: 50, y: 50 }).then(() => test.done());
}, "The setPointerCapture() method can throw.");

</script>
@@ -39,12 +39,16 @@

assert_equals(iframe.contentWindow.location.href, "about:blank", "The iframe initially has no URL.");

iframe.addEventListener("load", () => {
assert_true(iframe.contentWindow.location.href.includes("disabled.html"), "Upon navigation the URL has a location.");
test.done();
const loaded = new Promise(resolve => {
iframe.addEventListener("load", () => {
assert_true(iframe.contentWindow.location.href.includes("disabled.html"), "Upon navigation the URL has a location.");
resolve();
});
});

ui.tap({ x: 100, y: 100 });
const tapped = ui.tap({ x: 100, y: 100 });

Promise.all([loaded, tapped]).then(() => test.done());
}, "Testing that setting touch-action: none allows link traversal.");

</script>
@@ -19,11 +19,9 @@
target.style.touchAction = "pan-x pan-y";

ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
requestAnimationFrame(() => {
assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
test.done();
});
assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
test.done();
});

}, "Testing that setting 'touch-action: pan-x pan-y' on an element allows page scrolling in both axes.");
@@ -19,11 +19,9 @@
target.style.touchAction = "pan-x";

ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
requestAnimationFrame(() => {
assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
test.done();
});
assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
test.done();
});
}, "Testing that setting touch-action: pan-x on an element prevents page scrolling in the y-axis.");

@@ -19,11 +19,9 @@
target.style.touchAction = "pan-y";

ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
requestAnimationFrame(() => {
assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
test.done();
});
assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
test.done();
});
}, "Testing that setting touch-action: pan-y on an element prevents page scrolling in the x-axis.");

@@ -19,10 +19,8 @@
target.style.touchAction = "pinch-zoom";

ui.pinchOut({ x: 50, y: 50, width: 100, height: 100, scale: 0.5 }).then(() => {
requestAnimationFrame(() => {
assert_not_equals(window.internals.pageScaleFactor(), 1, "The page was scaled.");
test.done();
});
assert_not_equals(window.internals.pageScaleFactor(), 1, "The page was scaled.");
test.done();
});
}, "Testing that setting touch-action: pinch-zoom on an element allows page zooming.");

@@ -18,7 +18,7 @@

target.style.touchAction = "pan-x";

const eventTracker = new EventTracker(target, ["pointerdown", "pointermove", "pointerup", "pointercancel"]);
const eventTracker = new EventTracker(target, ["pointerdown", "pointerup", "pointercancel"]);

const one = ui.finger();
ui.sequence([
@@ -31,9 +31,6 @@
]).then(() => {
eventTracker.assertMatchesEvents([
{ type: "pointerdown" },
{ type: "pointermove" },
{ type: "pointermove" },
{ type: "pointermove" },
{ type: "pointercancel" }
]);
test.done();
@@ -18,7 +18,7 @@

target.style.touchAction = "pan-y";

const eventTracker = new EventTracker(target, ["pointerdown", "pointermove", "pointerup", "pointercancel"]);
const eventTracker = new EventTracker(target, ["pointerdown", "pointerup", "pointercancel"]);

const one = ui.finger();
ui.sequence([
@@ -31,9 +31,6 @@
]).then(() => {
eventTracker.assertMatchesEvents([
{ type: "pointerdown" },
{ type: "pointermove" },
{ type: "pointermove" },
{ type: "pointermove" },
{ type: "pointercancel" }
]);
test.done();
@@ -107,15 +107,12 @@ const ui = new (class UIController {
return this.fingers[id] = new Finger(id);
}

beginTouches(options)
{
return this._run(`uiController.touchDownAtPoint(${options.x}, ${options.y}, ${options.numberOfTouches || 1})`);
}

swipe(from, to)
{
const durationInSeconds = 0.5;
return this._run(`uiController.dragFromPointToPoint(${from.x}, ${from.y}, ${to.x}, ${to.y}, ${durationInSeconds})`);
const durationInSeconds = 0.1;
return new Promise(resolve => this._run(`uiController.dragFromPointToPoint(${from.x}, ${from.y}, ${to.x}, ${to.y}, ${durationInSeconds})`).then(() =>
setTimeout(resolve, durationInSeconds * 1000)
));
}

tap(options)
@@ -132,55 +129,30 @@ const ui = new (class UIController {
options.x = options.x || 0;
options.y = options.y || 0;

const startEvent = {
inputType : "hand",
timeOffset : 0,
touches : [
{ inputType : "finger",
phase : "moved",
id : 1,
x : options.x,
y : options.y,
pressure : 0
},
{ inputType : "finger",
phase : "moved",
id : 2,
x : (options.x + options.width) / options.scale,
y : (options.y + options.height) / options.scale,
pressure : 0
}
]
};

const endEvent = {
inputType : "hand",
timeOffset : 0.5,
touches : [
{ inputType : "finger",
phase : "moved",
id : 1,
x : options.x,
y : options.y,
pressure : 0
},
{ inputType : "finger",
phase : "moved",
id : 2,
x : options.x + options.width,
y : options.y + options.height,
pressure : 0
}
]
};

return this._runEvents([{
interpolate : "linear",
timestep: 0.1,
coordinateSpace : "content",
startEvent: startEvent,
endEvent: endEvent
}]);
const startPoint = { x: options.x + options.width, y: options.y + options.height };
const endPoint = { x: options.x + options.width * options.scale, y: options.y + options.height * options.scale };

function step(factor)
{
return {
x: endPoint.x + (startPoint.x - endPoint.x) * (1 - factor),
y: endPoint.y + (startPoint.y - endPoint.y) * (1 - factor)
};
}

const one = this.finger();
const two = this.finger();
return this.sequence([
one.begin({ x: options.x, y: options.y }),
two.begin(step(0)),
two.move(step(0.2)),
two.move(step(0.4)),
two.move(step(0.6)),
two.move(step(0.8)),
two.move(step(1)),
one.end(),
two.end()
]);
}

sequence(touches)
@@ -217,12 +189,12 @@ const ui = new (class UIController {
}));
}

beginStylus(options)
tapStylus(options)
{
options.azimuthAngle = options.azimuthAngle || 0;
options.altitudeAngle = options.altitudeAngle || 0;
options.pressure = options.pressure || 0;
return this._run(`uiController.stylusDownAtPoint(${options.x}, ${options.y}, ${options.azimuthAngle}, ${options.altitudeAngle}, ${options.pressure})`);
return this._run(`uiController.stylusTapAtPoint(${options.x}, ${options.y}, ${options.azimuthAngle}, ${options.altitudeAngle}, ${options.pressure})`);
}

_runEvents(events)

0 comments on commit f2af8e1

Please sign in to comment.