<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> <!-- XUL Widget Test for notificationbox --> <window title="Notification Box" width="500" height="600" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <notificationbox id="nb"/> <menupopup id="menupopup" onpopupshown="this.hidePopup()" onpopuphidden="checkPopupClosed()"> <menuitem label="One"/> </menupopup> <!-- test results are displayed in the html:body --> <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/> <!-- test code goes here --> <script type="application/javascript"><![CDATA[ SimpleTest.waitForExplicitFinish(); var testtag_notificationbox_buttons = [ { label: "Button 1", accesskey: "u", callback: testtag_notificationbox_buttonpressed, popup: "menupopup" } ]; var NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; function testtag_notificationbox_buttonpressed(event) { } function testtag_notificationbox(nb) { testtag_notificationbox_State(nb, "initial", null, 0); SimpleTest.is(nb.notificationsHidden, false, "initial notificationsHidden"); SimpleTest.is(nb.removeAllNotifications(false), undefined, "initial removeAllNotifications"); testtag_notificationbox_State(nb, "initial removeAllNotifications", null, 0); SimpleTest.is(nb.removeAllNotifications(true), undefined, "initial removeAllNotifications immediate"); testtag_notificationbox_State(nb, "initial removeAllNotifications immediate", null, 0); runTimedTests(tests, -1, nb, null); } var notification_last_events = []; function notification_eventCallback(event) { notification_last_events.push({ actualEvent: event , item: this }); } /** * For any notifications that have the notification_eventCallback on * them, we will have recorded instances of those callbacks firing * and stored them. This checks to see that the expected event types * are being fired in order, and targeting the right item. * * @param {Array<string>} expectedEvents * The list of event types, in order, that we expect to have been * fired on the item. * @param {<xul:notification>} ntf * The notification we expect the callback to have been fired from. * @param {string} testName * The name of the current test, for logging. */ function testtag_notification_eventCallback(expectedEvents, ntf, testName) { for (let i = 0; i < expectedEvents; ++i) { let expected = expectedEvents[i]; let { actualEvent, item } = notification_last_events[i]; SimpleTest.is(actualEvent, expected, testName + ": event name"); SimpleTest.is(item, ntf, testName + ": event item"); } notification_last_events = []; } var tests = [ { test: function(nb, ntf) { // append a new notification var ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification"); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "append", ntf, 1); testtag_notification_State(nb, ntf, "append", "Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW); // check the getNotificationWithValue method var ntf_found = nb.getNotificationWithValue("note"); SimpleTest.is(ntf, ntf_found, "getNotificationWithValue note"); var none_found = nb.getNotificationWithValue("notenone"); SimpleTest.is(none_found, null, "getNotificationWithValue null"); return ntf; } }, { test: function(nb, ntf) { // check that notifications can be removed properly nb.removeNotification(ntf); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "removeNotification", null, 0); // try removing the notification again to make sure an exception occurs var exh = false; try { nb.removeNotification(ntf); } catch (ex) { exh = true; } SimpleTest.is(exh, true, "removeNotification again"); testtag_notificationbox_State(nb, "removeNotification again", null, 0); } }, { test: function(nb, ntf) { // append a new notification, but now with an event callback var ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons, notification_eventCallback); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification with callback"); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "append with callback", ntf, 1); return ntf; } }, { test: function(nb, ntf) { nb.removeNotification(ntf); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "removeNotification with callback", null, 0); testtag_notification_eventCallback(["removed"], ntf, "removeNotification()"); return ntf; } }, { test: function(nb, ntf) { var ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons, notification_eventCallback); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification with callback"); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "append with callback", ntf, 1); return ntf; } }, { test: function(rb, ntf) { // Dismissing the notification instead of removing it should // fire a dismissed "event" on the callback, followed by // a removed "event". ntf.dismiss(); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "called dismiss()", null, 0); testtag_notification_eventCallback(["dismissed", "removed"], ntf, "dismiss()"); return ntf; } }, { test: function(nb, ntf) { // Create a popup to be used by a menu-button. var doc = nb.ownerDocument; var menuPopup = doc.createElementNS(NSXUL, "menupopup"); var menuItem = menuPopup.appendChild(doc.createElementNS(NSXUL, "menuitem")); menuItem.setAttribute("label", "Menu Item"); // Append a notification with a button of type 'menu-button'. ntf = nb.appendNotification( "Notification", "note", "happy.png", nb.PRIORITY_WARNING_LOW, [{ label: "Button", type: "menu-button", popup: menuPopup }] ); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "append", ntf, 1); testtag_notification_State(nb, ntf, "append", "Notification", "note", "happy.png", nb.PRIORITY_WARNING_LOW); var button = ntf.querySelector(".notification-button"); SimpleTest.is(button.type, "menu-button", "Button type should be set"); var menuPopup = button.getElementsByTagNameNS(NSXUL, "menupopup"); SimpleTest.is(menuPopup.length, 1, "There should be a menu attached"); var menuItem = menuPopup[0].firstChild; SimpleTest.is(menuItem.localName, "menuitem", "There should be a menu item"); SimpleTest.is(menuItem.getAttribute("label"), "Menu Item", "Label should match"); // Clean up. nb.removeNotification(ntf); return [1, null]; } }, { repeat: true, test: function(nb, arr) { var idx = arr[0]; var ntf = arr[1]; switch (idx) { case 1: // append a new notification ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification"); // Test persistence ntf.persistence++; return [idx, ntf]; case 2: case 3: nb.removeTransientNotifications(); return [idx, ntf]; } }, result: function(nb, arr) { var idx = arr[0]; var ntf = arr[1]; switch (idx) { case 1: testtag_notificationbox_State(nb, "notification added", ntf, 1); testtag_notification_State(nb, ntf, "append", "Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW); SimpleTest.is(ntf.persistence, 1, "persistence is 1"); return [++idx, ntf]; case 2: testtag_notificationbox_State(nb, "first removeTransientNotifications", ntf, 1); testtag_notification_State(nb, ntf, "append", "Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW); SimpleTest.is(ntf.persistence, 0, "persistence is now 0"); return [++idx, ntf]; case 3: testtag_notificationbox_State(nb, "second removeTransientNotifications", null, 0); this.repeat = false; } } }, { test: function(nb, ntf) { // append another notification var ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_MEDIUM, testtag_notificationbox_buttons); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification again"); return ntf; }, result: function(nb, ntf) { // check that appending a second notification after removing the first one works testtag_notificationbox_State(nb, "append again", ntf, 1); testtag_notification_State(nb, ntf, "append again", "Notification", "note", "happy.png", nb.PRIORITY_INFO_MEDIUM); return ntf; } }, { test: function(nb, ntf) { // check the removeCurrentNotification method nb.removeCurrentNotification(); return ntf; }, result: function(nb, ntf) { testtag_notificationbox_State(nb, "removeCurrentNotification", null, 0); } }, { test: function(nb, ntf) { var ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_HIGH, testtag_notificationbox_buttons); return ntf; }, result: function(nb, ntf) { // test the removeAllNotifications method testtag_notificationbox_State(nb, "append info_high", ntf, 1); SimpleTest.is(ntf.priority, nb.PRIORITY_INFO_HIGH, "notification.priority " + nb.PRIORITY_INFO_HIGH); SimpleTest.is(nb.removeAllNotifications(false), undefined, "removeAllNotifications"); } }, { test: function(nb, unused) { // add a number of notifications and check that they are added in order nb.appendNotification("Four", "4", null, nb.PRIORITY_INFO_HIGH, testtag_notificationbox_buttons); nb.appendNotification("Seven", "7", null, nb.PRIORITY_WARNING_HIGH, testtag_notificationbox_buttons); nb.appendNotification("Two", "2", null, nb.PRIORITY_INFO_LOW, null); nb.appendNotification("Eight", "8", null, nb.PRIORITY_CRITICAL_LOW, null); nb.appendNotification("Five", "5", null, nb.PRIORITY_WARNING_LOW, null); nb.appendNotification("Six", "6", null, nb.PRIORITY_WARNING_HIGH, null); nb.appendNotification("One", "1", null, nb.PRIORITY_INFO_LOW, null); nb.appendNotification("Nine", "9", null, nb.PRIORITY_CRITICAL_MEDIUM, null); var ntf = nb.appendNotification("Ten", "10", null, nb.PRIORITY_CRITICAL_HIGH, null); nb.appendNotification("Three", "3", null, nb.PRIORITY_INFO_MEDIUM, null); return ntf; }, result: function(nb, ntf) { SimpleTest.is(nb.currentNotification == ntf ? nb.currentNotification.value : null, "10", "appendNotification order"); return 1; } }, { // test closing notifications to make sure that the current notification is still set properly repeat: true, test: function(nb, testidx) { switch (testidx) { case 1: nb.getNotificationWithValue("10").close(); return [1, 9]; case 2: nb.removeNotification(nb.getNotificationWithValue("9")); return [2, 8]; case 3: nb.removeCurrentNotification(); return [3, 7]; case 4: nb.getNotificationWithValue("6").close(); return [4, 7]; case 5: nb.removeNotification(nb.getNotificationWithValue("5")); return [5, 7]; case 6: nb.removeCurrentNotification(); return [6, 4]; } }, result: function(nb, arr) { // arr is [testindex, expectedvalue] SimpleTest.is(nb.currentNotification.value, "" + arr[1], "close order " + arr[0]); SimpleTest.is(nb.allNotifications.length, 10 - arr[0], "close order " + arr[0] + " count"); if (arr[0] == 6) this.repeat = false; return ++arr[0]; } }, { test: function(nb, ntf) { var exh = false; try { nb.appendNotification("no", "no", "no", 0, null); } catch (ex) { exh = true; } SimpleTest.is(exh, true, "appendNotification priority too low"); exh = false; try { nb.appendNotification("no", "no", "no", 11, null); } catch (ex) { exh = true; } SimpleTest.is(exh, true, "appendNotification priority too high"); // check that the other priority types work properly runTimedTests(appendPriorityTests, -1, nb, nb.PRIORITY_WARNING_LOW); } } ]; var appendPriorityTests = [ { test: function(nb, priority) { var ntf = nb.appendNotification("Notification", "note", "happy.png", priority, testtag_notificationbox_buttons); SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification " + priority); return [ntf, priority]; }, result: function(nb, obj) { SimpleTest.is(obj[0].priority, obj[1], "notification.priority " + obj[1]); return obj[1]; } }, { test: function(nb, priority) { nb.removeCurrentNotification(); return priority; }, result: function(nb, priority) { if (priority == nb.PRIORITY_CRITICAL_BLOCK) { let ntf = nb.appendNotification("Notification", "note", "happy.png", nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons); setTimeout(checkPopupTest, 50, nb, ntf); } else { runTimedTests(appendPriorityTests, -1, nb, ++priority); } } } ]; function testtag_notificationbox_State(nb, testid, expecteditem, expectedcount) { SimpleTest.is(nb.currentNotification, expecteditem, testid + " currentNotification"); SimpleTest.is(nb.allNotifications ? nb.allNotifications.length : "no value", expectedcount, testid + " allNotifications"); } function testtag_notification_State(nb, ntf, testid, label, value, image, priority) { SimpleTest.is(ntf.control, nb, testid + " notification.control"); SimpleTest.is(ntf.label, label, testid + " notification.label"); SimpleTest.is(ntf.value, value, testid + " notification.value"); SimpleTest.is(ntf.image, image, testid + " notification.image"); SimpleTest.is(ntf.priority, priority, testid + " notification.priority"); var type; switch (priority) { case nb.PRIORITY_INFO_LOW: case nb.PRIORITY_INFO_MEDIUM: case nb.PRIORITY_INFO_HIGH: type = "info"; break; case nb.PRIORITY_WARNING_LOW: case nb.PRIORITY_WARNING_MEDIUM: case nb.PRIORITY_WARNING_HIGH: type = "warning"; break; case nb.PRIORITY_CRITICAL_LOW: case nb.PRIORITY_CRITICAL_MEDIUM: case nb.PRIORITY_CRITICAL_HIGH: case nb.PRIORITY_CRITICAL_BLOCK: type = "critical"; break; } SimpleTest.is(ntf.type, type, testid + " notification.type"); } function checkPopupTest(nb, ntf) { if (nb._animating) setTimeout(checkPopupTest, ntf); else { var evt = new Event(""); ntf.dispatchEvent(evt); evt.target.buttonInfo = testtag_notificationbox_buttons[0]; ntf._doButtonCommand(evt); } } function checkPopupClosed() { is(document.popupNode, null, "popupNode null after popup is closed"); SimpleTest.finish(); } /** * run one or more tests which perform a test operation, wait for a delay, * then perform a result operation. * * tests - array of objects where each object is : * { * test: test function, * result: result function * repeat: true to repeat the test * } * idx - starting index in tests * element - element to run tests on * arg - argument to pass between test functions * * If, after executing the result part, the repeat property of the test is * true, then the test is repeated. If the repeat property is not true, * continue on to the next test. * * The test and result functions take two arguments, the element and the arg. * The test function may return a value which will passed to the result * function as its arg. The result function may also return a value which * will be passed to the next repetition or the next test in the array. */ function runTimedTests(tests, idx, element, arg) { if (idx >= 0 && "result" in tests[idx]) arg = tests[idx].result(element, arg); // if not repeating, move on to the next test if (idx == -1 || !tests[idx].repeat) idx++; if (idx < tests.length) { var result = tests[idx].test(element, arg); setTimeout(runTimedTestsWait, 50, tests, idx, element, result); } } function runTimedTestsWait(tests, idx, element, arg) { // use this secret property to check if the animation is still running. If it // is, then the notification hasn't fully opened or closed yet if (element._animating) setTimeout(runTimedTestsWait, 50, tests, idx, element, arg); else runTimedTests(tests, idx, element, arg); } setTimeout(testtag_notificationbox, 0, document.getElementById('nb')); ]]> </script> </window>