from kivy.tests.common import GraphicUnitTest from kivy.lang import Builder from kivy.base import EventLoop from kivy.weakproxy import WeakProxy from kivy.input.motionevent import MotionEvent from time import sleep DropDown = None KV = ''' # +/- copied from ActionBar example + edited for the test FloatLayout: ActionBar: pos_hint: {'top': 1} ActionView: use_separator: True ActionPrevious: title: 'Action Bar' with_previous: False ActionOverflow: ActionButton: text: 'Btn0' icon: 'atlas://data/images/defaulttheme/audio-volume-high' ActionButton: text: 'Btn1' ActionButton: text: 'Btn2' ActionGroup: id: group1 text: 'group 1' ActionButton: id: group1button text: 'Btn3' on_release: setattr(root, 'g1button', True) ActionButton: text: 'Btn4' ActionGroup: id: group2 dropdown_width: 200 text: 'group 2' ActionButton: id: group2button text: 'Btn5' on_release: setattr(root, 'g2button', True) ActionButton: text: 'Btn6' ActionButton: text: 'Btn7' ''' class UTMotionEvent(MotionEvent): def depack(self, args): self.is_touch = True self.sx = args['x'] self.sy = args['y'] self.profile = ['pos'] super(UTMotionEvent, self).depack(args) class TouchPoint(UTMotionEvent): def __init__(self, raw_x, raw_y): win = EventLoop.window super(UTMotionEvent, self).__init__( "unittest", 1, { "x": raw_x / float(win.width), "y": raw_y / float(win.height), } ) # press & release EventLoop.post_dispatch_input("begin", self) EventLoop.post_dispatch_input("end", self) EventLoop.idle() class ActionBarTestCase(GraphicUnitTest): framecount = 0 def setUp(self): global DropDown from kivy.uix.dropdown import DropDown # kill KV lang logging (too long test) import kivy.lang.builder as builder if not hasattr(self, '_trace'): self._trace = builder.trace self.builder = builder builder.trace = lambda *_, **__: None super(ActionBarTestCase, self).setUp() def tearDown(self): # add the logging back import kivy.lang.builder as builder builder.trace = self._trace super(ActionBarTestCase, self).tearDown() def move_frames(self, t): for i in range(t): EventLoop.idle() def clean_garbage(self, *args): for child in self._win.children[:]: self._win.remove_widget(child) self.move_frames(5) def check_dropdown(self, present=True): any_list = [ isinstance(child, DropDown) for child in self._win.children ] # mustn't allow more than one DropDown opened! self.assertLess(sum(any_list), 2) # passed if not present and not any(any_list): return elif present and any(any_list): return print('DropDown either missing, or isn\'t supposed to be there') self.assertTrue(False) def test_1_openclose(self, *args): # click on Group 2 to open its DropDown # - DropDown shows up # then click away # - Group 2 DropDown disappears # click on Group 1 to open its DropDown # - DropDown shows up # then click away # - Group 1 DropDown disappears self._win = EventLoop.window self.clean_garbage() root = Builder.load_string(KV) self.render(root) self.assertLess(len(self._win.children), 2) group2 = root.ids.group2 group1 = root.ids.group1 self.move_frames(5) # no DropDown present yet self.check_dropdown(present=False) self.assertFalse(group2.is_open) self.assertFalse(group1.is_open) items = ((group2, group1), (group1, group2)) for item in items: active, passive = item # click on active Group TouchPoint(*active.center) # active Group DropDown shows up self.check_dropdown(present=True) gdd = WeakProxy(self._win.children[0]) # active Group DropDown == value in WeakProxy self.assertIn(gdd, self._win.children) self.assertEqual(gdd, self._win.children[0]) self.assertTrue(active.is_open) self.assertFalse(passive.is_open) # click away TouchPoint(0, 0) # wait for closed Group DropDown to disappear # go to the next frame after the DropDown disappeared sleep(gdd.min_state_time) self.move_frames(1) # no DropDown is open self.assertNotEqual(gdd, self._win.children[0]) self.assertLess(len(self._win.children), 2) self.check_dropdown(present=False) self.assertFalse(active.is_open) self.assertFalse(passive.is_open) self._win.remove_widget(root) def test_2_switch(self, *args): # click on Group 2 to open its DropDown # - DropDown shows up # then click on Group 1 to open its DropDown # - Group 2 DropDown disappears, Group 1 DropDown shows up # click away # - no DropDown is opened self._win = EventLoop.window self.clean_garbage() root = Builder.load_string(KV) self.render(root) self.assertLess(len(self._win.children), 2) group2 = root.ids.group2 group1 = root.ids.group1 self.move_frames(5) # no DropDown present yet self.check_dropdown(present=False) self.assertFalse(group2.is_open) self.assertFalse(group1.is_open) # click on Group 2 TouchPoint(*group2.center) # Group 2 DropDown shows up self.check_dropdown(present=True) g2dd = WeakProxy(self._win.children[0]) # Group 2 DropDown == value in WeakProxy self.assertIn(g2dd, self._win.children) self.assertEqual(g2dd, self._win.children[0]) self.assertTrue(group2.is_open) self.assertFalse(group1.is_open) # click away from ActionBar and wait for it to disappear TouchPoint(0, 0) sleep(g2dd.min_state_time) self.move_frames(1) # click on Group 1 TouchPoint(*group1.center) # wait for closed Group 2 DropDown to disappear # and for Group 1 DropDown to appear (there are 2 DDs now) # go to the next frame after the DropDown disappeared sleep(g2dd.min_state_time) self.move_frames(1) # Group 1 DropDown != value in WeakProxy (Group 2 DD) self.assertNotEqual(g2dd, self._win.children[0]) self.assertFalse(group2.is_open) self.assertTrue(group1.is_open) self.check_dropdown(present=True) # click away from ActionBar TouchPoint(0, 0) # wait for closed Group DropDown to disappear # go to the next frame after the DropDown disappeared sleep(g2dd.min_state_time) self.move_frames(1) # no DropDown present in Window self.check_dropdown(present=False) self.assertFalse(group2.is_open) self.assertFalse(group1.is_open) self.assertNotIn(g2dd, self._win.children) self._win.remove_widget(root) def test_3_openpress(self, *args): # click on Group 2 to open its DropDown # - DropDown shows up # then click on Group 2 DropDown button # - DropDown disappears # click on Group 1 to open its DropDown # - DropDown shows up # then click on Group 1 DropDown button # - DropDown disappears self._win = EventLoop.window self.clean_garbage() root = Builder.load_string(KV) self.render(root) self.assertLess(len(self._win.children), 2) group2 = root.ids.group2 group2button = root.ids.group2button group1 = root.ids.group1 group1button = root.ids.group1button self.move_frames(5) # no DropDown present yet self.check_dropdown(present=False) self.assertFalse(group2.is_open) self.assertFalse(group1.is_open) items = ( (group2, group1, group2button), (group1, group2, group1button) ) for item in items: active, passive, button = item # click on active Group TouchPoint(*active.center) # active Group DropDown shows up self.check_dropdown(present=True) gdd = WeakProxy(self._win.children[0]) # active Group DropDown == value in WeakProxy self.assertIn(gdd, self._win.children) self.assertEqual(gdd, self._win.children[0]) self.assertTrue(active.is_open) self.assertFalse(passive.is_open) # click on active Group DropDown Button (needed to_window) TouchPoint(*button.to_window(*button.center)) self.assertTrue(getattr( root, active.text[0::6] + 'button' )) # wait for closed Group DropDown to disappear # go to the next frame after the DropDown disappeared sleep(gdd.min_state_time) self.move_frames(1) # no DropDown is open self.assertNotEqual(gdd, self._win.children[0]) self.assertLess(len(self._win.children), 2) self.assertFalse(active.is_open) self.assertFalse(passive.is_open) self.check_dropdown(present=False) self._win.remove_widget(root) def test_4_openmulti(self, *args): # click on Group to open its DropDown # - DropDown shows up # then click on Group DropDown button # - DropDown disappears # repeat self._win = EventLoop.window self.clean_garbage() root = Builder.load_string(KV) self.render(root) self.assertLess(len(self._win.children), 2) group2 = root.ids.group2 group2button = root.ids.group2button group1 = root.ids.group1 group1button = root.ids.group1button self.move_frames(5) # no DropDown present yet self.check_dropdown(present=False) self.assertFalse(group2.is_open) items = ((group2, group2button), (group1, group1button)) for item in items: group, button = item for _ in range(5): # click on Group TouchPoint(*group.center) # Group DropDown shows up self.check_dropdown(present=True) gdd = WeakProxy(self._win.children[0]) # Group DropDown == value in WeakProxy self.assertIn(gdd, self._win.children) self.assertEqual(gdd, self._win.children[0]) self.assertTrue(group.is_open) # click on Group DropDown Button TouchPoint(*button.to_window(*button.center)) # wait for closed Group DropDown to disappear # go to the next frame after the DropDown disappeared sleep(gdd.min_state_time) self.move_frames(1) # no DropDown is open self.assertNotEqual(gdd, self._win.children[0]) self.assertFalse(group.is_open) self.check_dropdown(present=False) self._win.remove_widget(root) if __name__ == '__main__': import unittest unittest.main()