diff --git a/tests/uitests/details.py b/tests/uitests/details.py
new file mode 100644
index 000000000..a90bf6a8d
--- /dev/null
+++ b/tests/uitests/details.py
@@ -0,0 +1,84 @@
+import time
+import unittest
+
+import tests
+from tests.uitests import utils as uiutils
+
+import dogtail.rawinput
+import pyatspi
+
+
+class Details(unittest.TestCase):
+ """
+ UI tests for virt-manager's VM details window
+ """
+ def setUp(self):
+ self.app = uiutils.DogtailApp(tests.utils.uri_test)
+ def tearDown(self):
+ self.app.kill()
+
+
+ ###################
+ # Private helpers #
+ ###################
+
+ def _open_details_window(self, vmname="test-many-devices"):
+ uiutils.find_fuzzy(
+ self.app.root, vmname, "table cell").doubleClick()
+ win = uiutils.find_pattern(self.app.root, "%s on" % vmname, "frame")
+ uiutils.find_pattern(win, "Details", "radio button").click()
+ return win
+
+
+ ##############
+ # Test cases #
+ ##############
+
+ def testDetailsHardwareSmokeTest(self):
+ """
+ Open the VM with all the crazy hardware and just verify that each
+ HW panel shows itself without raising any error.
+ """
+ win = self._open_details_window()
+
+ # Ensure the Overview page is the first selected
+ uiutils.find_pattern(win, "Hypervisor Details", "label")
+ uiutils.find_pattern(win, "Overview", "table cell").click()
+
+ # After we hit this number of down presses, start checking for
+ # widget focus to determine if we hit the end of the list. We
+ # don't check for widget focus unconditionally because it's slow.
+ # The seemingly arbitrary number here is because it matches the
+ # number of devices in test-many-devices at the time of this writing.
+ check_after = 88
+
+ focused = None
+ old_focused = None
+ count = 0
+ while True:
+ count += 1
+ dogtail.rawinput.pressKey("Down")
+
+ if not win.getState().contains(pyatspi.STATE_ACTIVE):
+ # Should mean an error dialog popped up
+ uiutils.find_pattern(self.app.root, "Error", "alert")
+ raise AssertionError(
+ "One of the hardware pages raised an error")
+
+ if count < check_after:
+ time.sleep(.1)
+ continue
+
+ old_focused = focused
+ focused = uiutils.focused_nodes(win)
+ if old_focused is None:
+ continue
+
+ overlap = [w for w in old_focused if w in focused]
+ if len(overlap) == len(old_focused):
+ # Focus didn't change, meaning we hit the end of the HW list,
+ # so our testing is done
+ break
+
+ self.app.quit()
+ return
diff --git a/tests/uitests/utils.py b/tests/uitests/utils.py
index 7e43db516..3656268aa 100644
--- a/tests/uitests/utils.py
+++ b/tests/uitests/utils.py
@@ -87,6 +87,10 @@ class DogtailApp(object):
time.sleep(.5)
+#########################
+# Widget search helpers #
+#########################
+
def find_pattern(root, name, roleName=None, labeller_text=None):
"""
Search root for any widget that contains the passed name/role regex
@@ -120,6 +124,26 @@ def find_fuzzy(root, name, roleName=None, labeller_text=None):
labeller_pattern)
+def check_in_loop(func, timeout=-1):
+ """
+ Run the passed func in a loop every .5 seconds until timeout is hit or
+ the func returns True.
+ If timeout=-1, check indefinitely.
+ """
+ total_time = 0.0
+ while True:
+ time.sleep(.5)
+ total_time += .5
+ if func() is True:
+ return
+ if timeout > 0 and total_time >= timeout:
+ raise RuntimeError("Loop condition wasn't met")
+
+
+#####################
+# Debugging helpers #
+#####################
+
def node_string(node):
msg = "name='%s' roleName='%s'" % (node.name, node.roleName)
if node.labeller:
@@ -141,17 +165,15 @@ def print_nodes(root):
root.findChildren(_walk, isLambda=True)
-def check_in_loop(func, timeout=-1):
+def focused_nodes(root):
"""
- Run the passed func in a loop every .5 seconds until timeout is hit or
- the func returns True.
- If timeout=-1, check indefinitely.
+ Return a list of all focused nodes. Useful for debugging
"""
- total_time = 0.0
- while True:
- time.sleep(.5)
- total_time += .5
- if func() is True:
- return
- if timeout > 0 and total_time >= timeout:
- raise RuntimeError("Loop condition wasn't met")
+ def _walk(node):
+ try:
+ if node.focused:
+ return node
+ except Exception, e:
+ print "got exception: %s" % e
+
+ return root.findChildren(_walk, isLambda=True)
diff --git a/ui/details.ui b/ui/details.ui
index 8b231046c..f76a8eb07 100644
--- a/ui/details.ui
+++ b/ui/details.ui
@@ -617,6 +617,16 @@
+
+
+
+
+
+
+