browser/modules/test/browser_SignInToWebsite.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 * http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 "use strict";
michael@0 5
michael@0 6 /**
michael@0 7 * TO TEST:
michael@0 8 * - test state saved on doorhanger dismissal
michael@0 9 * - links to switch steps
michael@0 10 * - TOS and PP link clicks
michael@0 11 * - identityList is populated correctly
michael@0 12 */
michael@0 13
michael@0 14 Services.prefs.setBoolPref("toolkit.identity.debug", true);
michael@0 15
michael@0 16 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
michael@0 17 "resource://gre/modules/identity/Identity.jsm");
michael@0 18
michael@0 19 const TEST_ORIGIN = "https://example.com";
michael@0 20 const TEST_EMAIL = "user@example.com";
michael@0 21
michael@0 22 let gTestIndex = 0;
michael@0 23 let outerWinId = gBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 24 .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
michael@0 25
michael@0 26 function NotificationBase(aNotId) {
michael@0 27 this.id = aNotId;
michael@0 28 }
michael@0 29 NotificationBase.prototype = {
michael@0 30 message: TEST_ORIGIN,
michael@0 31 mainAction: {
michael@0 32 label: "",
michael@0 33 callback: function() {
michael@0 34 this.mainActionClicked = true;
michael@0 35 }.bind(this),
michael@0 36 },
michael@0 37 secondaryActions: [],
michael@0 38 options: {
michael@0 39 "identity": {
michael@0 40 origin: TEST_ORIGIN,
michael@0 41 rpId: outerWinId,
michael@0 42 },
michael@0 43 },
michael@0 44 };
michael@0 45
michael@0 46 let tests = [
michael@0 47 {
michael@0 48 name: "test_request_required_typed",
michael@0 49
michael@0 50 run: function() {
michael@0 51 setupRPFlow();
michael@0 52 this.notifyOptions = {
michael@0 53 rpId: outerWinId,
michael@0 54 origin: TEST_ORIGIN,
michael@0 55 };
michael@0 56 this.notifyObj = new NotificationBase("identity-request");
michael@0 57 Services.obs.notifyObservers({wrappedJSObject: this.notifyOptions},
michael@0 58 "identity-request", null);
michael@0 59 },
michael@0 60
michael@0 61 onShown: function(popup) {
michael@0 62 checkPopup(popup, this.notifyObj);
michael@0 63 let notification = popup.childNodes[0];
michael@0 64
michael@0 65 // Check identity popup state
michael@0 66 let state = notification.identity;
michael@0 67 ok(!state.typedEmail, "Nothing should be typed yet");
michael@0 68 ok(!state.selected, "Identity should not be selected yet");
michael@0 69 ok(!state.termsOfService, "No TOS specified");
michael@0 70 ok(!state.privacyPolicy, "No PP specified");
michael@0 71 is(state.step, 0, "Step should be persisted with default value");
michael@0 72 is(state.rpId, outerWinId, "Check rpId");
michael@0 73 is(state.origin, TEST_ORIGIN, "Check origin");
michael@0 74
michael@0 75 is(notification.step, 0, "Should be on the new email step");
michael@0 76 is(notification.chooseEmailLink.hidden, true, "Identity list is empty so link to list view should be hidden");
michael@0 77 is(notification.addEmailLink.parentElement.hidden, true, "We are already on the email input step so choose email pane should be hidden");
michael@0 78 is(notification.emailField.value, "", "Email field should default to empty on a new notification");
michael@0 79 let notifDoc = notification.ownerDocument;
michael@0 80 ok(notifDoc.getAnonymousElementByAttribute(notification, "anonid", "tos").hidden,
michael@0 81 "TOS link should be hidden");
michael@0 82 ok(notifDoc.getAnonymousElementByAttribute(notification, "anonid", "privacypolicy").hidden,
michael@0 83 "PP link should be hidden");
michael@0 84
michael@0 85 // Try to continue with a missing email address
michael@0 86 triggerMainCommand(popup);
michael@0 87 is(notification.throbber.style.visibility, "hidden", "is throbber visible");
michael@0 88 ok(!notification.button.disabled, "Button should not be disabled");
michael@0 89 is(window.gIdentitySelected, null, "Check no identity selected");
michael@0 90
michael@0 91 // Fill in an invalid email address and try again
michael@0 92 notification.emailField.value = "foo";
michael@0 93 triggerMainCommand(popup);
michael@0 94 is(notification.throbber.style.visibility, "hidden", "is throbber visible");
michael@0 95 ok(!notification.button.disabled, "Button should not be disabled");
michael@0 96 is(window.gIdentitySelected, null, "Check no identity selected");
michael@0 97
michael@0 98 // Fill in an email address and try again
michael@0 99 notification.emailField.value = TEST_EMAIL;
michael@0 100 triggerMainCommand(popup);
michael@0 101 is(window.gIdentitySelected.rpId, outerWinId, "Check identity selected rpId");
michael@0 102 is(window.gIdentitySelected.identity, TEST_EMAIL, "Check identity selected email");
michael@0 103 is(notification.identity.selected, TEST_EMAIL, "Check persisted email");
michael@0 104 is(notification.throbber.style.visibility, "visible", "is throbber visible");
michael@0 105 ok(notification.button.disabled, "Button should be disabled");
michael@0 106 ok(notification.emailField.disabled, "Email field should be disabled");
michael@0 107 ok(notification.identityList.disabled, "Identity list should be disabled");
michael@0 108
michael@0 109 PopupNotifications.getNotification("identity-request").remove();
michael@0 110 },
michael@0 111
michael@0 112 onHidden: function(popup) { },
michael@0 113 },
michael@0 114 {
michael@0 115 name: "test_request_optional",
michael@0 116
michael@0 117 run: function() {
michael@0 118 this.notifyOptions = {
michael@0 119 rpId: outerWinId,
michael@0 120 origin: TEST_ORIGIN,
michael@0 121 privacyPolicy: TEST_ORIGIN + "/pp.txt",
michael@0 122 termsOfService: TEST_ORIGIN + "/tos.tzt",
michael@0 123 };
michael@0 124 this.notifyObj = new NotificationBase("identity-request");
michael@0 125 Services.obs.notifyObservers({ wrappedJSObject: this.notifyOptions },
michael@0 126 "identity-request", null);
michael@0 127 },
michael@0 128
michael@0 129 onShown: function(popup) {
michael@0 130 checkPopup(popup, this.notifyObj);
michael@0 131 let notification = popup.childNodes[0];
michael@0 132
michael@0 133 // Check identity popup state
michael@0 134 let state = notification.identity;
michael@0 135 ok(!state.typedEmail, "Nothing should be typed yet");
michael@0 136 ok(!state.selected, "Identity should not be selected yet");
michael@0 137 is(state.termsOfService, this.notifyOptions.termsOfService, "Check TOS URL");
michael@0 138 is(state.privacyPolicy, this.notifyOptions.privacyPolicy, "Check PP URL");
michael@0 139 is(state.step, 0, "Step should be persisted with default value");
michael@0 140 is(state.rpId, outerWinId, "Check rpId");
michael@0 141 is(state.origin, TEST_ORIGIN, "Check origin");
michael@0 142
michael@0 143 is(notification.step, 0, "Should be on the new email step");
michael@0 144 is(notification.chooseEmailLink.hidden, true, "Identity list is empty so link to list view should be hidden");
michael@0 145 is(notification.addEmailLink.parentElement.hidden, true, "We are already on the email input step so choose email pane should be hidden");
michael@0 146 is(notification.emailField.value, "", "Email field should default to empty on a new notification");
michael@0 147 let notifDoc = notification.ownerDocument;
michael@0 148 let tosLink = notifDoc.getAnonymousElementByAttribute(notification, "anonid", "tos");
michael@0 149 ok(!tosLink.hidden, "TOS link should be visible");
michael@0 150 is(tosLink.href, this.notifyOptions.termsOfService, "Check TOS link URL");
michael@0 151 let ppLink = notifDoc.getAnonymousElementByAttribute(notification, "anonid", "privacypolicy");
michael@0 152 ok(!ppLink.hidden, "PP link should be visible");
michael@0 153 is(ppLink.href, this.notifyOptions.privacyPolicy, "Check PP link URL");
michael@0 154
michael@0 155 // Try to continue with a missing email address
michael@0 156 triggerMainCommand(popup);
michael@0 157 is(notification.throbber.style.visibility, "hidden", "is throbber visible");
michael@0 158 ok(!notification.button.disabled, "Button should not be disabled");
michael@0 159 is(window.gIdentitySelected, null, "Check no identity selected");
michael@0 160
michael@0 161 // Fill in an invalid email address and try again
michael@0 162 notification.emailField.value = "foo";
michael@0 163 triggerMainCommand(popup);
michael@0 164 is(notification.throbber.style.visibility, "hidden", "is throbber visible");
michael@0 165 ok(!notification.button.disabled, "Button should not be disabled");
michael@0 166 is(window.gIdentitySelected, null, "Check no identity selected");
michael@0 167
michael@0 168 // Fill in an email address and try again
michael@0 169 notification.emailField.value = TEST_EMAIL;
michael@0 170 triggerMainCommand(popup);
michael@0 171 is(window.gIdentitySelected.rpId, outerWinId, "Check identity selected rpId");
michael@0 172 is(window.gIdentitySelected.identity, TEST_EMAIL, "Check identity selected email");
michael@0 173 is(notification.identity.selected, TEST_EMAIL, "Check persisted email");
michael@0 174 is(notification.throbber.style.visibility, "visible", "is throbber visible");
michael@0 175 ok(notification.button.disabled, "Button should be disabled");
michael@0 176 ok(notification.emailField.disabled, "Email field should be disabled");
michael@0 177 ok(notification.identityList.disabled, "Identity list should be disabled");
michael@0 178
michael@0 179 PopupNotifications.getNotification("identity-request").remove();
michael@0 180 },
michael@0 181
michael@0 182 onHidden: function(popup) {},
michael@0 183 },
michael@0 184 {
michael@0 185 name: "test_login_state_changed",
michael@0 186 run: function () {
michael@0 187 this.notifyOptions = {
michael@0 188 rpId: outerWinId,
michael@0 189 };
michael@0 190 this.notifyObj = new NotificationBase("identity-logged-in");
michael@0 191 this.notifyObj.message = "Signed in as: user@example.com";
michael@0 192 this.notifyObj.mainAction.label = "Sign Out";
michael@0 193 this.notifyObj.mainAction.accessKey = "O";
michael@0 194 Services.obs.notifyObservers({ wrappedJSObject: this.notifyOptions },
michael@0 195 "identity-login-state-changed", TEST_EMAIL);
michael@0 196 executeSoon(function() {
michael@0 197 PopupNotifications.getNotification("identity-logged-in").anchorElement.click();
michael@0 198 });
michael@0 199 },
michael@0 200
michael@0 201 onShown: function(popup) {
michael@0 202 checkPopup(popup, this.notifyObj);
michael@0 203
michael@0 204 // Fire the notification that the user is no longer logged-in to close the UI.
michael@0 205 Services.obs.notifyObservers({ wrappedJSObject: this.notifyOptions },
michael@0 206 "identity-login-state-changed", null);
michael@0 207 },
michael@0 208
michael@0 209 onHidden: function(popup) {},
michael@0 210 },
michael@0 211 {
michael@0 212 name: "test_login_state_changed_logout",
michael@0 213 run: function () {
michael@0 214 this.notifyOptions = {
michael@0 215 rpId: outerWinId,
michael@0 216 };
michael@0 217 this.notifyObj = new NotificationBase("identity-logged-in");
michael@0 218 this.notifyObj.message = "Signed in as: user@example.com";
michael@0 219 this.notifyObj.mainAction.label = "Sign Out";
michael@0 220 this.notifyObj.mainAction.accessKey = "O";
michael@0 221 Services.obs.notifyObservers({ wrappedJSObject: this.notifyOptions },
michael@0 222 "identity-login-state-changed", TEST_EMAIL);
michael@0 223 executeSoon(function() {
michael@0 224 PopupNotifications.getNotification("identity-logged-in").anchorElement.click();
michael@0 225 });
michael@0 226 },
michael@0 227
michael@0 228 onShown: function(popup) {
michael@0 229 checkPopup(popup, this.notifyObj);
michael@0 230
michael@0 231 // This time trigger the Sign Out button and make sure the UI goes away.
michael@0 232 triggerMainCommand(popup);
michael@0 233 },
michael@0 234
michael@0 235 onHidden: function(popup) {},
michael@0 236 },
michael@0 237 ];
michael@0 238
michael@0 239 function test_auth() {
michael@0 240 let notifyOptions = {
michael@0 241 provId: outerWinId,
michael@0 242 origin: TEST_ORIGIN,
michael@0 243 };
michael@0 244
michael@0 245 Services.obs.addObserver(function() {
michael@0 246 // prepare to send auth-complete and close the window
michael@0 247 let winCloseObs = new WindowObserver(function(closedWin) {
michael@0 248 info("closed window");
michael@0 249 finish();
michael@0 250 }, "domwindowclosed");
michael@0 251 Services.ww.registerNotification(winCloseObs);
michael@0 252 Services.obs.notifyObservers(null, "identity-auth-complete", IdentityService.IDP.authenticationFlowSet.authId);
michael@0 253
michael@0 254 }, "test-identity-auth-window", false);
michael@0 255
michael@0 256 let winObs = new WindowObserver(function(authWin) {
michael@0 257 ok(authWin, "Authentication window opened");
michael@0 258 ok(authWin.contentWindow.location);
michael@0 259 });
michael@0 260
michael@0 261 Services.ww.registerNotification(winObs);
michael@0 262
michael@0 263 Services.obs.notifyObservers({ wrappedJSObject: notifyOptions },
michael@0 264 "identity-auth", TEST_ORIGIN + "/auth");
michael@0 265 }
michael@0 266
michael@0 267 function test() {
michael@0 268 waitForExplicitFinish();
michael@0 269
michael@0 270 let sitw = {};
michael@0 271 try {
michael@0 272 Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
michael@0 273 } catch (ex) {
michael@0 274 ok(true, "Skip the test since SignInToWebsite.jsm isn't packaged outside outside mozilla-central");
michael@0 275 finish();
michael@0 276 return;
michael@0 277 }
michael@0 278
michael@0 279 PopupNotifications.transitionsEnabled = false;
michael@0 280
michael@0 281 registerCleanupFunction(cleanUp);
michael@0 282
michael@0 283 ok(sitw.SignInToWebsiteUX, "SignInToWebsiteUX object exists");
michael@0 284 if (!Services.prefs.getBoolPref("dom.identity.enabled")) {
michael@0 285 // If the pref isn't enabled then init wasn't called so do that for the test.
michael@0 286 sitw.SignInToWebsiteUX.init();
michael@0 287 }
michael@0 288
michael@0 289 // Replace implementation of ID Service functions for testing
michael@0 290 window.selectIdentity = sitw.SignInToWebsiteUX.selectIdentity;
michael@0 291 sitw.SignInToWebsiteUX.selectIdentity = function(aRpId, aIdentity) {
michael@0 292 info("Identity selected: " + aIdentity);
michael@0 293 window.gIdentitySelected = {rpId: aRpId, identity: aIdentity};
michael@0 294 };
michael@0 295
michael@0 296 window.setAuthenticationFlow = IdentityService.IDP.setAuthenticationFlow;
michael@0 297 IdentityService.IDP.setAuthenticationFlow = function(aAuthId, aProvId) {
michael@0 298 info("setAuthenticationFlow: " + aAuthId + " : " + aProvId);
michael@0 299 this.authenticationFlowSet = { authId: aAuthId, provId: aProvId };
michael@0 300 Services.obs.notifyObservers(null, "test-identity-auth-window", aAuthId);
michael@0 301 };
michael@0 302
michael@0 303 runNextTest();
michael@0 304 }
michael@0 305
michael@0 306 // Cleanup between tests
michael@0 307 function resetState() {
michael@0 308 delete window.gIdentitySelected;
michael@0 309 delete IdentityService.IDP.authenticationFlowSet;
michael@0 310 IdentityService.reset();
michael@0 311 }
michael@0 312
michael@0 313 // Cleanup after all tests
michael@0 314 function cleanUp() {
michael@0 315 info("cleanup");
michael@0 316 resetState();
michael@0 317
michael@0 318 PopupNotifications.transitionsEnabled = true;
michael@0 319
michael@0 320 for (let topic in gActiveObservers)
michael@0 321 Services.obs.removeObserver(gActiveObservers[topic], topic);
michael@0 322 for (let eventName in gActiveListeners)
michael@0 323 PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false);
michael@0 324 delete IdentityService.RP._rpFlows[outerWinId];
michael@0 325
michael@0 326 // Put the JSM functions back to how they were
michael@0 327 IdentityService.IDP.setAuthenticationFlow = window.setAuthenticationFlow;
michael@0 328 delete window.setAuthenticationFlow;
michael@0 329
michael@0 330 let sitw = {};
michael@0 331 Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
michael@0 332 sitw.SignInToWebsiteUX.selectIdentity = window.selectIdentity;
michael@0 333 delete window.selectIdentity;
michael@0 334 if (!Services.prefs.getBoolPref("dom.identity.enabled")) {
michael@0 335 sitw.SignInToWebsiteUX.uninit();
michael@0 336 }
michael@0 337
michael@0 338 Services.prefs.clearUserPref("toolkit.identity.debug");
michael@0 339 }
michael@0 340
michael@0 341 let gActiveListeners = {};
michael@0 342 let gActiveObservers = {};
michael@0 343 let gShownState = {};
michael@0 344
michael@0 345 function runNextTest() {
michael@0 346 let nextTest = tests[gTestIndex];
michael@0 347
michael@0 348 function goNext() {
michael@0 349 resetState();
michael@0 350 if (++gTestIndex == tests.length)
michael@0 351 executeSoon(test_auth);
michael@0 352 else
michael@0 353 executeSoon(runNextTest);
michael@0 354 }
michael@0 355
michael@0 356 function addObserver(topic) {
michael@0 357 function observer() {
michael@0 358 Services.obs.removeObserver(observer, "PopupNotifications-" + topic);
michael@0 359 delete gActiveObservers["PopupNotifications-" + topic];
michael@0 360
michael@0 361 info("[Test #" + gTestIndex + "] observer for " + topic + " called");
michael@0 362 nextTest[topic]();
michael@0 363 goNext();
michael@0 364 }
michael@0 365 Services.obs.addObserver(observer, "PopupNotifications-" + topic, false);
michael@0 366 gActiveObservers["PopupNotifications-" + topic] = observer;
michael@0 367 }
michael@0 368
michael@0 369 if (nextTest.backgroundShow) {
michael@0 370 addObserver("backgroundShow");
michael@0 371 } else if (nextTest.updateNotShowing) {
michael@0 372 addObserver("updateNotShowing");
michael@0 373 } else {
michael@0 374 doOnPopupEvent("popupshowing", function () {
michael@0 375 info("[Test #" + gTestIndex + "] popup showing");
michael@0 376 });
michael@0 377 doOnPopupEvent("popupshown", function () {
michael@0 378 gShownState[gTestIndex] = true;
michael@0 379 info("[Test #" + gTestIndex + "] popup shown");
michael@0 380 nextTest.onShown(this);
michael@0 381 });
michael@0 382
michael@0 383 // We allow multiple onHidden functions to be defined in an array. They're
michael@0 384 // called in the order they appear.
michael@0 385 let onHiddenArray = nextTest.onHidden instanceof Array ?
michael@0 386 nextTest.onHidden :
michael@0 387 [nextTest.onHidden];
michael@0 388 doOnPopupEvent("popuphidden", function () {
michael@0 389 if (!gShownState[gTestIndex]) {
michael@0 390 // TODO: needed?
michael@0 391 info("Popup from test " + gTestIndex + " was hidden before its popupshown fired");
michael@0 392 }
michael@0 393
michael@0 394 let onHidden = onHiddenArray.shift();
michael@0 395 info("[Test #" + gTestIndex + "] popup hidden (" + onHiddenArray.length + " hides remaining)");
michael@0 396 executeSoon(function () {
michael@0 397 onHidden.call(nextTest, this);
michael@0 398 if (!onHiddenArray.length)
michael@0 399 goNext();
michael@0 400 }.bind(this));
michael@0 401 }, onHiddenArray.length);
michael@0 402 info("[Test #" + gTestIndex + "] added listeners; panel state: " + PopupNotifications.isPanelOpen);
michael@0 403 }
michael@0 404
michael@0 405 info("[Test #" + gTestIndex + "] running test");
michael@0 406 nextTest.run();
michael@0 407 }
michael@0 408
michael@0 409 function doOnPopupEvent(eventName, callback, numExpected) {
michael@0 410 gActiveListeners[eventName] = function (event) {
michael@0 411 if (event.target != PopupNotifications.panel)
michael@0 412 return;
michael@0 413 if (typeof(numExpected) === "number")
michael@0 414 numExpected--;
michael@0 415 if (!numExpected) {
michael@0 416 PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false);
michael@0 417 delete gActiveListeners[eventName];
michael@0 418 }
michael@0 419
michael@0 420 callback.call(PopupNotifications.panel);
michael@0 421 };
michael@0 422 PopupNotifications.panel.addEventListener(eventName, gActiveListeners[eventName], false);
michael@0 423 }
michael@0 424
michael@0 425 function checkPopup(popup, notificationObj) {
michael@0 426 info("[Test #" + gTestIndex + "] checking popup");
michael@0 427
michael@0 428 let notifications = popup.childNodes;
michael@0 429 is(notifications.length, 1, "only one notification displayed");
michael@0 430 let notification = notifications[0];
michael@0 431 let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
michael@0 432 is(notification.getAttribute("label"), notificationObj.message, "message matches");
michael@0 433 is(notification.id, notificationObj.id + "-notification", "id matches");
michael@0 434 if (notificationObj.id != "identity-request" && notificationObj.mainAction) {
michael@0 435 is(notification.getAttribute("buttonlabel"), notificationObj.mainAction.label, "main action label matches");
michael@0 436 is(notification.getAttribute("buttonaccesskey"), notificationObj.mainAction.accessKey, "main action accesskey matches");
michael@0 437 }
michael@0 438 let actualSecondaryActions = notification.childNodes;
michael@0 439 let secondaryActions = notificationObj.secondaryActions || [];
michael@0 440 let actualSecondaryActionsCount = actualSecondaryActions.length;
michael@0 441 if (secondaryActions.length) {
michael@0 442 let lastChild = actualSecondaryActions.item(actualSecondaryActions.length - 1);
michael@0 443 is(lastChild.tagName, "menuseparator", "menuseparator exists");
michael@0 444 actualSecondaryActionsCount--;
michael@0 445 }
michael@0 446 is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");
michael@0 447 secondaryActions.forEach(function (a, i) {
michael@0 448 is(actualSecondaryActions[i].getAttribute("label"), a.label, "label for secondary action " + i + " matches");
michael@0 449 is(actualSecondaryActions[i].getAttribute("accesskey"), a.accessKey, "accessKey for secondary action " + i + " matches");
michael@0 450 });
michael@0 451 }
michael@0 452
michael@0 453 function triggerMainCommand(popup) {
michael@0 454 info("[Test #" + gTestIndex + "] triggering main command");
michael@0 455 let notifications = popup.childNodes;
michael@0 456 ok(notifications.length > 0, "at least one notification displayed");
michael@0 457 let notification = notifications[0];
michael@0 458
michael@0 459 // 20, 10 so that the inner button is hit
michael@0 460 EventUtils.synthesizeMouse(notification.button, 20, 10, {});
michael@0 461 }
michael@0 462
michael@0 463 function triggerSecondaryCommand(popup, index) {
michael@0 464 info("[Test #" + gTestIndex + "] triggering secondary command");
michael@0 465 let notifications = popup.childNodes;
michael@0 466 ok(notifications.length > 0, "at least one notification displayed");
michael@0 467 let notification = notifications[0];
michael@0 468
michael@0 469 notification.button.focus();
michael@0 470
michael@0 471 popup.addEventListener("popupshown", function () {
michael@0 472 popup.removeEventListener("popupshown", arguments.callee, false);
michael@0 473
michael@0 474 // Press down until the desired command is selected
michael@0 475 for (let i = 0; i <= index; i++)
michael@0 476 EventUtils.synthesizeKey("VK_DOWN", {});
michael@0 477
michael@0 478 // Activate
michael@0 479 EventUtils.synthesizeKey("VK_RETURN", {});
michael@0 480 }, false);
michael@0 481
michael@0 482 // One down event to open the popup
michael@0 483 EventUtils.synthesizeKey("VK_DOWN", { altKey: (navigator.platform.indexOf("Mac") == -1) });
michael@0 484 }
michael@0 485
michael@0 486 function dismissNotification(popup) {
michael@0 487 info("[Test #" + gTestIndex + "] dismissing notification");
michael@0 488 executeSoon(function () {
michael@0 489 EventUtils.synthesizeKey("VK_ESCAPE", {});
michael@0 490 });
michael@0 491 }
michael@0 492
michael@0 493 function partial(fn) {
michael@0 494 let args = Array.prototype.slice.call(arguments, 1);
michael@0 495 return function() {
michael@0 496 return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
michael@0 497 };
michael@0 498 }
michael@0 499
michael@0 500 // create a mock "doc" object, which the Identity Service
michael@0 501 // uses as a pointer back into the doc object
michael@0 502 function mock_doc(aIdentity, aOrigin, aDoFunc) {
michael@0 503 let mockedDoc = {};
michael@0 504 mockedDoc.id = outerWinId;
michael@0 505 mockedDoc.loggedInEmail = aIdentity;
michael@0 506 mockedDoc.origin = aOrigin;
michael@0 507 mockedDoc['do'] = aDoFunc;
michael@0 508 mockedDoc.doReady = partial(aDoFunc, 'ready');
michael@0 509 mockedDoc.doLogin = partial(aDoFunc, 'login');
michael@0 510 mockedDoc.doLogout = partial(aDoFunc, 'logout');
michael@0 511 mockedDoc.doError = partial(aDoFunc, 'error');
michael@0 512 mockedDoc.doCancel = partial(aDoFunc, 'cancel');
michael@0 513 mockedDoc.doCoffee = partial(aDoFunc, 'coffee');
michael@0 514
michael@0 515 return mockedDoc;
michael@0 516 }
michael@0 517
michael@0 518 // takes a list of functions and returns a function that
michael@0 519 // when called the first time, calls the first func,
michael@0 520 // then the next time the second, etc.
michael@0 521 function call_sequentially() {
michael@0 522 let numCalls = 0;
michael@0 523 let funcs = arguments;
michael@0 524
michael@0 525 return function() {
michael@0 526 if (!funcs[numCalls]) {
michael@0 527 let argString = Array.prototype.slice.call(arguments).join(",");
michael@0 528 ok(false, "Too many calls: " + argString);
michael@0 529 return;
michael@0 530 }
michael@0 531 funcs[numCalls].apply(funcs[numCalls], arguments);
michael@0 532 numCalls += 1;
michael@0 533 };
michael@0 534 }
michael@0 535
michael@0 536 function setupRPFlow(aIdentity) {
michael@0 537 IdentityService.RP.watch(mock_doc(aIdentity, TEST_ORIGIN, call_sequentially(
michael@0 538 function(action, params) {
michael@0 539 is(action, "ready", "1st callback");
michael@0 540 is(params, null);
michael@0 541 },
michael@0 542 function(action, params) {
michael@0 543 is(action, "logout", "2nd callback");
michael@0 544 is(params, null);
michael@0 545 },
michael@0 546 function(action, params) {
michael@0 547 is(action, "ready", "3rd callback");
michael@0 548 is(params, null);
michael@0 549 }
michael@0 550 )));
michael@0 551 }
michael@0 552
michael@0 553 function WindowObserver(aCallback, aObserveTopic = "domwindowopened") {
michael@0 554 this.observe = function(aSubject, aTopic, aData) {
michael@0 555 if (aTopic != aObserveTopic) {
michael@0 556 return;
michael@0 557 }
michael@0 558 info(aObserveTopic);
michael@0 559 Services.ww.unregisterNotification(this);
michael@0 560
michael@0 561 SimpleTest.executeSoon(function() {
michael@0 562 let domWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
michael@0 563 aCallback(domWin);
michael@0 564 });
michael@0 565 };
michael@0 566 }

mercurial