Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Flowery.NET.RuntimeTests/Controls/DaisyTourTestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ internal static async Task CleanupAsync(Control root, DaisyTour tour)
await SettleAsync(root);
}

// Waits until the pointer in the middle of a control hits it. Hit testing reads the rendered scene, and after a
// control moved, a slow compositor (Xvfb) can show the old place for more than the frames WaitForRenderAsync waits.
internal static Task WaitUntilHitAsync(Control control) => RuntimeTestHelpers.WaitUntilAsync(() =>
{
var root = TopLevel.GetTopLevel(control)!;
var center = control.TranslatePoint(new Point(control.Bounds.Width / 2, control.Bounds.Height / 2), root);
return center is { } point && root.InputHitTest(point) is Visual hit
&& (ReferenceEquals(hit, control) || control.IsVisualAncestorOf(hit));
}, $"the pointer hits the moved {control.GetType().Name}");

// Presses the left button in the middle of a control like the mouse does: the element under the pointer takes
// the capture and receives the press, which bubbles to the control. The control must be what the pointer hits.
internal static (TopLevel Root, Point Start, Pointer Pointer) PressAtCenter(Control control, PointerType type = PointerType.Mouse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ await InEditorAsync(async (tour, root) =>
MoveCaptured(first, top, new Point(start.X - 60, start.Y - 40));
await SettleAsync(root);
// Hit testing sees the moved grip once it has been rendered.
await RuntimeTestHelpers.WaitForRenderAsync();
await WaitUntilHitAsync(grip);

// The second finger presses, moves and lifts while the first one still holds the grip. It moves sideways,
// where the card text cannot scroll, so the scroll gesture does not take it before its release.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ await InEditorAsync(async (tour, editor) =>

// A second finger on the grip neither moves the origin of the drag nor resizes, and its release does not
// end the resize of the first finger. Hit testing sees the moved grip once it has been rendered.
await RuntimeTestHelpers.WaitForRenderAsync();
await WaitUntilHitAsync(thumb);
var (_, otherStart, second) = PressAtCenter(thumb, PointerType.Touch);
var otherEnd = new Point(otherStart.X - 90, otherStart.Y);
MoveCaptured(second, root, otherEnd);
Expand All @@ -155,7 +155,7 @@ await InEditorAsync(async (tour, editor) =>

// Once the first finger has finished, a third one resizes on its own, and its release away from its last
// move sets the width.
await RuntimeTestHelpers.WaitForRenderAsync();
await WaitUntilHitAsync(thumb);
var before = editor.InspectorBounds.Width;
var (_, thirdStart, third) = PressAtCenter(thumb, PointerType.Touch);
await ChangeGeometryAsync(tour, () => MoveCaptured(third, root, new Point(thirdStart.X - 20, thirdStart.Y)));
Expand Down
9 changes: 8 additions & 1 deletion scripts/check_android_gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,14 @@ def dump(self, name):
root = ElementTree.fromstring(data).find("node")
if root is None:
raise RuntimeError("uiautomator dumped an empty hierarchy")
return Node(root)
node = Node(root)
# A slow emulator can show "<system app> isn't responding" over the Gallery. Wait closes the dialog, and the
# dump counts as failed, so the next one sees the Gallery.
wait = node.find(name="android:id/aerr_wait")
if wait is not None:
self.tap(wait)
raise RuntimeError("a not-responding dialog of the system covered the screen")
return node

def shot(self, name):
data = adb("exec-out", "screencap", "-p", binary=True)
Expand Down
8 changes: 7 additions & 1 deletion scripts/test_check_android_gallery.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests how check_android_gallery.py takes failed and empty UI dumps.
"""Tests how check_android_gallery.py takes failed and empty UI dumps and dialogs of the system.

python3 -B -m unittest discover -s scripts -p "test_*.py"
"""
Expand Down Expand Up @@ -65,6 +65,12 @@ def test_an_empty_hierarchy_is_a_failed_dump(self):
self.use(FakeDevice(EMPTY))
self.assertIsNone(self.check.wait_for("1-home", lambda root: root.find(kind="HomePage"), 0))

def test_a_not_responding_dialog_of_the_system_is_closed_with_wait(self):
device = self.use(FakeDevice(hierarchy(("Button", "android:id/aerr_wait")), hierarchy(("HomePage", ""))))
home = self.check.wait_for("1-home", lambda root: root.find(kind="HomePage"), 30)
self.assertEqual("HomePage", home.kind)
self.assertEqual(1, device.taps)

def test_opening_the_sidebar_waits_out_failed_dumps(self):
device = self.use(FakeDevice(RuntimeError("uiautomator failed"), EMPTY, b"<hierarchy",
hierarchy(("Button", "HamburgerButton")),
Expand Down
Loading