The event queue in PyAuto offers a non-polling solution to observing Chrome events in functional tests. Events are held in the event queue in FIFO order until they can be handled by your PyAuto test. For full examples see chrome/test/functional/apptest.py. Observing DOM EventsTests for extensions and apps typically need to watch for changes to a web page. Here is a simple code snippet showing use of WaitForDomNode to navigate to a web page and wait for a div containing a number to appear: class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.NavigateToURL('hello.html') self.WaitForDomNode('//div', expected_value='^\d+$')Inside an iframe:class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.NavigateToURL('hello.html') self.WaitForDomNode('//div', expected_value='^\d+$', frame_xpath='/descendant::iframe[1]')class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.NavigateToURL('hello.html') self.WaitForDomNode('//div', expected_value='^\d+$', frame_xpath='/descendant::iframe[1]\n/descendant::iframe[1]')In an extension panel:class PyAutoEventExample(pyauto.PyUITest): def __init__(self, extension_id): self.extension_id = extension_id def _GetTabInfo(self, url_query): windows = self.GetBrowserInfo()['windows'] for win in windows: for tab in win['tabs']: if tab['url'] and url_query in tab['url']: return win['index'] return None def testBasic(self): self.InstallAndLaunchExtension(self.extension_id) # Code not shown. self.WaitForDomNode('//div', expected_value='^\d+$', windex=self._GetTabInfo('chrome-extension://%s/panel.html' % self.extension_id))Inside the OOBE on Chrome OS:class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.WaitForDomNode('//div', expected_value='^\d+$', exec_js=pyauto.PyUITest.ExecuteJavascriptInOOBEWebUI)Observing Javascript NotificationsJavascript can communicate directly with a PyAuto test using the event queue. When the Javascript wants to send an event notification it calls window.domAutomationController.sendWithId, like so: function NotifyTest(success) { if (window.domAutomationController) window.domAutomationController.sendWithId(4444, success ? 'success' : 'failure');}The corresponding PyAuto test has previously created an observer and is waiting for the Javascript notification: class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.AddDomEventObserver(automation_id=4444) self.NavigateToURL('test.html') assert self.GetNextEvent().get('name') == 'success'This is only a simple example. The event queue can hold an unlimited number of events, supporting use as a general asynchronous packet-based communication channel from Javascript (or Chrome) to a PyAuto test. When the event queue is empty, by default PyAuto's GetNextEvent() will block until an event occurs. A call with blocking disabled, GetNextEvent(blocking=False), will immediately return None if there is no event notification in the queue. Here's an hypothetical example that loads a web page 1000 times, checking that Chrome did not raise a generic PyAuto event after each load: class PyAutoEventExample(pyauto.PyUITest): def testBasic(self): self.AddPyAutoEventObserver(recurring=True) for x in xrange(1000): self.NavigateToURL('foo.html?x=%d' % x) assert self.GetNextEvent(blocking=False) is NoneBy default GetNextEvent() watches for all events. However, it can also be used to watch for an event from a specific observer. This allows multiple observers to be used at the same time without interference. In this example two observers are used, one of which is recurring. The example counts how many times a Javascript event notification is sent to the recurring observer before a link appears on the page. def count_events(self): event_id = self.AddDomEventObserver(automation_id=4444, recurring=True) dom_id = self.AddDomMutationObserver('exists', '//a') self.GetNextEvent(dom_id) total = 0 while self.GetNextEvent(event_id, blocking=False): total += 1 return totalEvent observers are deleted using PyAuto's RemoveEventObserver(id) method. Observers created with recurring=True will continue to watch for events and generate notifications until explicitly deleted. Event observers can also be used to watch for error conditions, after which they may need to be removed. This example is an improved version of the example for multiple event observers. Here the recurring event observer is deleted before counting the events in the queue: def count_events(self): event_id = self.AddDomEventObserver(automation_id=4444, recurring=True) dom_id = self.AddDomMutationObserver('exists', '//a') self.GetNextEvent(dom_id) self.RemoveEventObserver(event_id) total = 0 while self.GetNextEvent(event_id, blocking=False): total += 1 return totalClearing the Event QueueThe state of the entire event queue can be cleared using PyAuto's ClearEventQueue(). This will remove all event observers and delete all events in the queue. WIP |
