summaryrefslogtreecommitdiffstats
path: root/chrome/test
diff options
context:
space:
mode:
authorkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 20:18:45 +0000
committerkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 20:18:45 +0000
commitac43f703a731d232ea095c28a5367f2cdd2bd7b2 (patch)
treeac0c6932285989054cea2c5c8445f31c89364b6e /chrome/test
parent248e199c68b9e77b20450ef6851676bd43f8394c (diff)
downloadchromium_src-ac43f703a731d232ea095c28a5367f2cdd2bd7b2.zip
chromium_src-ac43f703a731d232ea095c28a5367f2cdd2bd7b2.tar.gz
chromium_src-ac43f703a731d232ea095c28a5367f2cdd2bd7b2.tar.bz2
Add pyauto hook for HTML5 notifications, tests, and helpers.
BUG=55125 TEST=none Review URL: http://codereview.chromium.org/3822001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63935 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/data/notifications/notification_tester.html98
-rw-r--r--chrome/test/functional/PYAUTO_TESTS1
-rw-r--r--chrome/test/functional/notifications.py337
-rw-r--r--chrome/test/pyautolib/pyauto.py63
4 files changed, 499 insertions, 0 deletions
diff --git a/chrome/test/data/notifications/notification_tester.html b/chrome/test/data/notifications/notification_tester.html
new file mode 100644
index 0000000..7a4aec3
--- /dev/null
+++ b/chrome/test/data/notifications/notification_tester.html
@@ -0,0 +1,98 @@
+<html>
+<!--notification_tester.html
+Script with javascript functions for creating and canceling notifications.
+Also can be used to request permission for notifications.
+-->
+<script>
+
+// Array of all notifications this page has created.
+var g_notifications = [];
+// Whether the site has requested and been granted permission.
+var g_permissionGranted = false;
+
+// Creates a notification with a iconUrl, title, text, and replaceId.
+// Returns an id for the notification, which can be used to cancel it with
+// |cancelNotification|. If two notifications are created with the same
+// replaceId, the second one should replace the first.
+function createNotification(iconUrl, title, text, replaceId) {
+ try {
+ var note = webkitNotifications.createNotification(iconUrl,
+ title,
+ text);
+ } catch (exception) {
+ sendResultToTest(-1);
+ return;
+ }
+ sendResultToTest(createNotificationHelper(note, replaceId));
+}
+
+// Creates an HTML notification with a given content url.
+// Returns an id for the notification, which can be used to cancel it with
+// |cancelNotification|. If two notifications are created with the same
+// replaceId, the second one should replace the first. If the notification
+// cannot be created, this returns -1.
+function createHTMLNotification(contentUrl, replaceId) {
+ try {
+ var note = webkitNotifications.createHTMLNotification(contentUrl);
+ } catch (exception) {
+ sendResultToTest(-1);
+ return;
+ }
+ sendResultToTest(createNotificationHelper(note, replaceId));
+}
+
+// Cancels a notification with the given id. Returns 1 on success.
+function cancelNotification(id) {
+ if (id < 0 || id > g_notifications.length) {
+ var errorMsg = "Attempted to cancel notification with invalid ID.\n" +
+ "ID: " + id + "\n# of notifications: " + g_notifications.length;
+ window.domAutomationController.send(errorMsg);
+ alert(errorMsg);
+ }
+ g_notifications[id].cancel();
+ sendResultToTest(1);
+}
+
+// Requests permission for this origin to create notifications.
+function requestPermission() {
+ window.webkitNotifications.requestPermission(onPermissionGranted);
+ sendResultToTest(1);
+}
+
+// Waits for the permission to create notifications to be granted.
+function waitForPermissionGranted() {
+ if (g_permissionGranted) {
+ sendResultToTest(1);
+ } else {
+ setTimeout(waitForPermissionGranted, 50);
+ }
+}
+
+// Callback for requesting notification privileges.
+function onPermissionGranted() {
+ g_permissionGranted = true;
+}
+
+// Helper function that shows the notification and adds it to
+// |g_notifications|.
+function createNotificationHelper(note, replaceId) {
+ note.show();
+ // |push| returns the length of the array after the add.
+ return g_notifications.push(note) - 1;
+}
+
+// Sends a result back to the main test logic.
+function sendResultToTest(result) {
+ // Convert the result to a string.
+ var stringResult = "" + result;
+ if (typeof stringResult != "string")
+ stringResult = JSON.stringify(result);
+ window.domAutomationController.send(stringResult);
+}
+
+</script>
+
+<body>
+This page is used for testing HTML5 notifications.
+</body>
+</html>
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index d5fbea8..87f8641 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -39,6 +39,7 @@
'imports',
'infobars',
'navigation',
+ 'notifications',
'omnibox',
'passwords',
'plugins',
diff --git a/chrome/test/functional/notifications.py b/chrome/test/functional/notifications.py
new file mode 100644
index 0000000..1cf414b
--- /dev/null
+++ b/chrome/test/functional/notifications.py
@@ -0,0 +1,337 @@
+#!/usr/bin/python
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import urllib
+
+import pyauto_functional
+import pyauto
+
+
+class NotificationsTest(pyauto.PyUITest):
+ """Test of HTML5 desktop notifications."""
+ def __init__(self, methodName='runTest'):
+ super(NotificationsTest, self).__init__(methodName)
+ self.NO_SUCH_URL = 'http://no_such_url_exists/'
+ # Content settings for default notification permission.
+ self.ALLOW_ALL_SETTING = 1
+ self.DENY_ALL_SETTING = 2
+ self.ASK_SETTING = 3
+
+ # HTML page used for notification testing.
+ self.TEST_PAGE_URL = (
+ self.GetFileURLForDataPath('notifications/notification_tester.html'))
+
+ def Debug(self):
+ """Test method for experimentation.
+
+ This method will not run automatically.
+ """
+ while True:
+ raw_input('Interact with the browser and hit <enter> to dump notification'
+ 'state...')
+ print '*' * 20
+ import pprint
+ pp = pprint.PrettyPrinter(indent=2)
+ pp.pprint(self.GetActiveNotifications())
+
+ def _SetDefaultPermissionSetting(self, setting):
+ """Sets the default setting for whether sites are allowed to create
+ notifications.
+ """
+ self.SetPrefs(pyauto.kDesktopNotificationDefaultContentSetting, setting)
+
+ def _GetDefaultPermissionSetting(self):
+ """Gets the default setting for whether sites are allowed to create
+ notifications.
+ """
+ return self.GetPrefsInfo().Prefs(
+ pyauto.kDesktopNotificationDefaultContentSetting)
+
+ def _GetDeniedOrigins(self):
+ """Gets the list of origins that are explicitly denied to create
+ notifications.
+ """
+ return self.GetPrefsInfo().Prefs(pyauto.kDesktopNotificationDeniedOrigins)
+
+ def _GetAllowedOrigins(self):
+ """Gets the list of origins that are explicitly allowed to create
+ notifications.
+ """
+ return self.GetPrefsInfo().Prefs(pyauto.kDesktopNotificationAllowedOrigins)
+
+ def _SetAllowedOrigins(self, origins):
+ """Sets the list of allowed origins to the given list.
+
+ None of the items in the list should be explicitly denied.
+ """
+ return self.SetPrefs(pyauto.kDesktopNotificationAllowedOrigins, origins)
+
+ def _SetDeniedOrigins(self, origins):
+ """Sets the list of denied origins to the given list.
+
+ None of the items in the list should be explicitly allowed.
+ """
+ return self.SetPrefs(pyauto.kDesktopNotificationDeniedOrigins, origins)
+
+ def _DenyOrigin(self, new_origin):
+ """Denies the given origin to create notifications.
+
+ If it was explicitly allowed, that preference is dropped.
+ """
+ self._DropOriginPreference(new_origin)
+ denied = self._GetDeniedOrigins() or []
+ if new_origin not in denied:
+ self._SetDeniedOrigins(denied + [new_origin])
+
+ def _AllowOrigin(self, new_origin):
+ """Allows the given origin to create notifications. If it was explicitly
+ denied, that preference is dropped.
+ """
+ self._DropOriginPreference(new_origin)
+ allowed = self._GetAllowedOrigins() or []
+ if new_origin not in allowed:
+ self._SetAllowedOrigins(allowed + [new_origin])
+
+ def _DropOriginPreference(self, new_origin):
+ """Drops the preference as to whether this origin should be allowed to
+ create notifications. If it was explicitly allowed or explicitly denied,
+ that preference is removed.
+ """
+ allowed = self._GetAllowedOrigins()
+ if allowed and new_origin in allowed:
+ allowed.remove(new_origin)
+ self._SetAllowedOrigins(allowed)
+ denied = self._GetDeniedOrigins()
+ if denied and new_origin in denied:
+ denied.remove(new_origin)
+ self._SetDeniedOrigins(denied)
+
+ def _AllowAllOrigins(self):
+ """Allows any origin to create notifications."""
+ self._SetDefaultPermissionSetting(self.ALLOW_ALL_SETTING)
+ self._SetDeniedOrigins([])
+
+ def _VerifyInfobar(self, origin, tab_index=0, windex=0):
+ """Helper to verify the notification infobar contents are correct.
+
+ Defaults to first tab in first window.
+
+ Args:
+ origin: origin of the notification, e.g., www.gmail.com
+ tab_index: index of the tab within the given window
+ windex: index of the window
+ """
+ tab_info = self.GetBrowserInfo()['windows'][windex]['tabs'][tab_index]
+ self.assertEquals(1, len(tab_info['infobars']))
+ infobar = tab_info['infobars'][0]
+ text = 'Allow %s to show desktop notifications?' % origin
+ self.assertEqual(text, infobar['text'])
+ self.assertEqual(2, len(infobar['buttons']))
+ self.assertEqual('Allow', infobar['buttons'][0])
+ self.assertEqual('Deny', infobar['buttons'][1])
+
+ def _CallJavascriptFunc(self, function, args=[], tab_index=0, windex=0):
+ """Helper function to execute a script that calls a given function.
+
+ Defaults to first tab in first window.
+
+ Args:
+ function: name of the function
+ args: list of all the arguments to pass into the called function. These
+ should be able to be converted to a string using the |str| function.
+ tab_index: index of the tab within the given window
+ windex: index of the window
+ """
+ # Convert the given arguments for evaluation in a javascript statement.
+ converted_args = []
+ for arg in args:
+ # If it is a string argument, we need to quote and escape it properly.
+ if type(arg) == type('string') or type(arg) == type(u'unicode'):
+ # We must convert all " in the string to \", so that we don't try
+ # to evaluate invalid javascript like ""arg"".
+ converted_arg = '"' + arg.replace('"', '\\"') + '"'
+ else:
+ # Convert it to a string so that we can use |join| later.
+ converted_arg = str(arg)
+ converted_args += [converted_arg]
+ js = '%s(%s)' % (function, ', '.join(converted_args))
+ return self.ExecuteJavascript(js, windex, tab_index)
+
+ def _CreateSimpleNotification(self, img_url, title, text,
+ replace_id='', tab_index=0, windex=0):
+ """Creates a simple notification.
+
+ Returns the id of the notification, which can be used to cancel it later.
+
+ This executes a script in the page which shows a notification.
+ This will only work if the page is navigated to |TEST_PAGE_URL|.
+ The page must also have permission to show notifications.
+
+ Args:
+ img_url: url of a image to use; can be a data url
+ title: title of the notification
+ text: text in the notification
+ replace_id: id string to be used for this notification. If another
+ notification is shown with the same replace_id, the former
+ will be replaced.
+ tab_index: index of the tab within the given window
+ windex: index of the window
+ """
+ return self._CallJavascriptFunc('createNotification',
+ [img_url, title, text, replace_id],
+ tab_index,
+ windex);
+
+ def _CreateHTMLNotification(self, content_url, replace_id='', tab_index=0,
+ windex=0):
+ """Creates an HTML notification.
+
+ Returns the id of the notification, which can be used to cancel it later.
+
+ This executes a script in the page which shows a notification.
+ This will only work if the page is navigated to |TEST_PAGE_URL|.
+ The page must also have permission to show notifications.
+
+ Args:
+ content_url: url of the page to show in the notification
+ replace_id: id string to be used for this notification. If another
+ notification is shown with the same replace_id, the former
+ will be replaced.
+ tab_index: index of the tab within the given window
+ windex: index of the window
+ """
+ return self._CallJavascriptFunc('createHTMLNotification',
+ [content_url, replace_id],
+ tab_index,
+ windex)
+
+ def _RequestPermission(self, tab_index=0, windex=0):
+ """Requests permission to create notifications.
+
+ This will only work if the current page is navigated to |TEST_PAGE_URL|.
+
+ Args:
+ tab_index: index of the tab within the given window
+ windex: index of the window
+ """
+ self._CallJavascriptFunc('requestPermission', [], windex, tab_index)
+
+ def _CancelNotification(self, notification_id, tab_index=0, windex=0):
+ """Cancels a notification with the given id.
+
+ This canceling is done in the page that showed that notification and so
+ follows a different path than closing a notification via the UI.
+
+ A notification can be canceled even if it has not been shown yet.
+ This will only work if the page is navigated to |TEST_PAGE_URL|.
+
+ Args:
+ tab_index: index of the tab within the given window that created the
+ notification
+ windex: index of the window
+ """
+ self._CallJavascriptFunc(
+ 'cancelNotification', [notification_id], tab_index, windex)
+
+ def testCreateSimpleNotification(self):
+ """Creates a simple notification."""
+ self._AllowAllOrigins()
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ self._CreateSimpleNotification('no_such_file.png', 'My Title', 'My Body')
+ self.assertEquals(len(self.GetActiveNotifications()), 1)
+ notification = self.GetActiveNotifications()[0]
+ html_data = urllib.unquote(notification['content_url'])
+ self.assertTrue('no_such_file.png' in html_data)
+ self.assertTrue('My Title' in html_data)
+ self.assertTrue('My Body' in html_data)
+
+ def testCreateHTMLNotification(self):
+ """Creates an HTML notification using a fake url."""
+ self._AllowAllOrigins()
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ self._CreateHTMLNotification(self.NO_SUCH_URL)
+ self.assertEquals(len(self.GetActiveNotifications()), 1)
+ notification = self.GetActiveNotifications()[0]
+ self.assertEquals(self.NO_SUCH_URL, notification['content_url'])
+ self.assertEquals('', notification['display_source'])
+ self.assertEquals('file:///', notification['origin_url'])
+
+ def testCloseNotification(self):
+ """Creates a notification and closes it."""
+ self._AllowAllOrigins()
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ self._CreateHTMLNotification(self.NO_SUCH_URL)
+ self.CloseNotification(0)
+ self.assertEquals(len(self.GetActiveNotifications()), 0)
+
+ def testCancelNotification(self):
+ """Creates a notification and cancels it in the origin page."""
+ self._AllowAllOrigins()
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ note_id = self._CreateHTMLNotification(self.NO_SUCH_URL)
+ self.assertNotEquals(-1, note_id)
+ self._CancelNotification(note_id)
+ self.assertEquals(len(self.GetActiveNotifications()), 0)
+
+ def testPermissionInfobarAppears(self):
+ """Requests notification privileges and verifies the infobar appears."""
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ self._RequestPermission()
+ self.assertTrue(self.WaitForInfobarCount(1))
+ self.assertEquals(len(self.GetActiveNotifications()), 0)
+ self._VerifyInfobar('') # file:/// origins are blank
+
+ def testAllowOnPermissionInfobar(self):
+ """Tries to create a notification and clicks allow on the infobar."""
+ self.NavigateToURL(self.TEST_PAGE_URL)
+ # This notification should not be shown because we don't have permission.
+ self._CreateHTMLNotification(self.NO_SUCH_URL)
+ self.assertEquals(len(self.GetActiveNotifications()), 0)
+
+ self._RequestPermission()
+ self.assertTrue(self.WaitForInfobarCount(1))
+ self.PerformActionOnInfobar('accept', infobar_index=0)
+ self._CreateHTMLNotification(self.NO_SUCH_URL)
+ self.WaitForNotificationCount(1)
+
+ def testOriginPreferencesBasic(self):
+ """Tests that we can allow and deny origins."""
+ altavista = 'www.altavista.com'
+ gmail = 'www.gmail.com'
+ yahoo = 'www.yahoo.com'
+ self._SetDeniedOrigins([altavista, gmail])
+ self.assertEquals(altavista, self._GetDeniedOrigins()[0])
+ self.assertEquals(gmail, self._GetDeniedOrigins()[1])
+ self._DenyOrigin(yahoo)
+ self.assertEquals(yahoo, self._GetDeniedOrigins()[2])
+ self.assertEquals(3, len(self._GetDeniedOrigins()))
+ self._DropOriginPreference(gmail)
+ self.assertEquals(2, len(self._GetDeniedOrigins()))
+ self.assertFalse(gmail in self._GetDeniedOrigins())
+
+ self._AllowOrigin(yahoo)
+ self.assertEquals(1, len(self._GetDeniedOrigins()))
+ self.assertFalse(yahoo in self._GetDeniedOrigins())
+ self.assertTrue(yahoo in self._GetAllowedOrigins())
+
+ self._SetAllowedOrigins([altavista, gmail])
+ self._SetDeniedOrigins([])
+ self.assertEquals(altavista, self._GetAllowedOrigins()[0])
+ self.assertEquals(gmail, self._GetAllowedOrigins()[1])
+ self._AllowOrigin(yahoo)
+ self.assertEquals(yahoo, self._GetAllowedOrigins()[2])
+ self.assertEquals(3, len(self._GetAllowedOrigins()))
+ self._DropOriginPreference(gmail)
+ self.assertEquals(2, len(self._GetAllowedOrigins()))
+ self.assertFalse(gmail in self._GetAllowedOrigins())
+
+ self._DenyOrigin(yahoo)
+ self.assertEquals(1, len(self._GetAllowedOrigins()))
+ self.assertTrue(yahoo in self._GetDeniedOrigins())
+ self.assertFalse(yahoo in self._GetAllowedOrigins())
+
+
+if __name__ == '__main__':
+ pyauto_functional.Main()
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index 02d342e..60b4728 100644
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -188,6 +188,15 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
return 'file://' + quoted_path
@staticmethod
+ def GetFileURLForDataPath(relative_path):
+ """Get file:// url for the given path relative to the chrome test data dir.
+
+ Also quotes the url using urllib.quote().
+ """
+ return PyUITest.GetFileURLForPath(
+ os.path.join(PyUITest.DataDir(), relative_path))
+
+ @staticmethod
def IsMac():
"""Are we on Mac?"""
return 'darwin' == sys.platform
@@ -1497,6 +1506,60 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
}
return self._GetResultFromJSONRequest(cmd_dict)
+ def GetActiveNotifications(self):
+ """Gets a list of the currently active/shown HTML5 notifications.
+
+ Returns:
+ a list containing info about each active notification, with the
+ first item in the list being the notification on the bottom of the
+ notification stack. The 'content_url' key can refer to a URL or a data
+ URI.
+
+ SAMPLE:
+ [ { u'content_url': u'data:text/html;charset=utf-8,%3C!DOCTYPE%l%3E%0Atm...'
+ u'display_source': 'www.corp.google.com',
+ u'origin_url': 'http://www.corp.google.com/'},
+ { u'content_url': 'http://www.gmail.com/special_notification.html',
+ u'display_source': 'www.gmail.com',
+ u'origin_url': 'http://www.gmail.com/'}]
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'GetActiveNotifications',
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['notifications']
+
+ def CloseNotification(self, index):
+ """Closes the active HTML5 notification at the given index.
+
+ Args:
+ index: the index of the notification to close. 0 refers to the
+ notification on the bottom of the notification stack.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'CloseNotification',
+ 'index': index,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)
+
+ def WaitForNotificationCount(self, count):
+ """Waits for the number of active HTML5 notifications to reach the given
+ count.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'WaitForNotificationCount',
+ 'count': count,
+ }
+ self._GetResultFromJSONRequest(cmd_dict)
+
def FindInPage(self, search_string, forward=True,
match_case=False, find_next=False,
tab_index=0, windex=0):