Skip to content
Snippets Groups Projects
helpers.js 10.4 KiB
Newer Older
/*jshint browser: true laxbreak: true, expr: true */
/*global BrowserID: true, ok: true, equal: true, start: true, deepEqual: true, notEqual: true */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

BrowserID.TestHelpers = (function() {
  "use strict";

  var bid = BrowserID,
      mediator = bid.Mediator,
      network = bid.Network,
      user = bid.User,
      xhr = bid.XHR,
      transport = bid.Mocks.xhr,
      provisioning = bid.Mocks.Provisioning,
      tooltip = bid.Tooltip,
      testOrigin = "https://login.persona.org";

  function register(message, cb) {
    registrations.push(mediator.subscribe(message, function(msg, info) {
      if(calls[msg]) {
        throw msg + " triggered more than once";
      }
      calls[msg] = info || true;
      cb && cb.apply(null, arguments);
    }));
  }

  function unregisterAll() {
    for(var i = 0, registration; registration = registrations[i]; ++i) {
      mediator.unsubscribe(registration);
    }
    registrations = [];
    calls = {};
  }

  function checkNetworkError() {
    ok($("#error .contents").text().length, "contents have been written");
    ok($("#error #action").text().length, "action contents have been written");
    ok($("#error #network").text().length, "network contents have been written");
  }

  function clearStorage() {
    for(var key in localStorage) {
      localStorage.removeItem(key);
    }
  }

      unregisterAll();
      mediator.reset();
      xhr.init({
        transport: transport,
        time_until_delay: TestHelpers.XHR_TIME_UNTIL_DELAY
      });

      transport.setDelay(0);
      transport.setContextInfo("auth_level", undefined);
      transport.setContextInfo("cookies_enabled", true);
      network.init({ forceCookieStatus: undefined });
      clearStorage();
      $("body").stop().show();
      $("body")[0].className = "";

      $(".error").removeClass("error");
      $(".notification").stop().hide();
      screens.wait.hide();
      screens.error.hide();
      tooltip.reset();
      provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
      user.init({
        provisioning: provisioning
      });
      user.setOrigin(testOrigin);
    },

    teardown: function() {
      unregisterAll();
      mediator.reset();
      clearStorage();
      screens.wait.hide();
      screens.error.hide();
      tooltip.reset();
      provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
      return message in calls;
    testTriggered: function(message, expectedFields) {
      ok(message in calls, message + " was triggered");
      if (expectedFields) this.testObjectValuesEqual(calls[message], expectedFields);
    expectedMessage: function(message, expectedFields) {
    // keep track of the original start function.  When the start function is
    // called, call the proxy start function and then the original start
    // function.  This allows proxy start functions to be chained and multiple
    // expectedMessages to be called.
    start = function(origStart) {
      TestHelpers.testTriggered(message, expectedFields);
      start = origStart;
      start();
    }.bind(null, start);

    register(message);
  },

  unexpectedMessage: function(message) {
    // keep track of the original start function.  When the start function is
    // called, call the proxy start function and then the original start
    // function.  This allows proxy start functions to be chained and multiple
    // expectedMessages to be called.
    start = function(origStart) {
      equal(TestHelpers.isTriggered(message), false, message + " was not triggered");
      start = origStart;
      start();

    }.bind(null, start);
    register(message);
  },


    errorVisible: function() {
      return screens.error.visible;
    testErrorVisible: function() {
      equal(TestHelpers.errorVisible(), true, "error screen is visible");
    testErrorNotVisible: function() {
      equal(TestHelpers.errorVisible(), false, "error screen is not visible");
    },

    waitVisible: function() {
      return screens.wait.visible;
    },

    testWaitVisible: function() {
      equal(TestHelpers.waitVisible(), true, "wait screen is visible");
    },

    delayVisible: function() {
      return screens.delay.visible;
    },

    testDelayVisible: function() {
      equal(TestHelpers.delayVisible(), true, "delay screen is visible");
    },

    checkNetworkError: checkNetworkError,
    unexpectedSuccess: function() {
      ok(false, "unexpected success");
      start();
    },

      ok(true, "expected XHR failure");
      start();
    },

    unexpectedXHRFailure: function() {
      ok(false, "unexpected XHR failure");
      start();
    },

    testTooltipVisible: function() {
      equal(tooltip.shown, true, "tooltip is visible");
    testTooltipNotVisible: function() {
      equal(tooltip.shown, false, "tooltip is not visible");
Shane Tomlinson's avatar
Shane Tomlinson committed
    },

    failureCheck: function failureCheck(cb) {
      // Take the original arguments, take off the function.  Add any additional
      // arguments that were passed in, and then tack on the onSuccess and
      // onFailure to the end.  Then call the callback.
      var args = [].slice.call(arguments, 1);

      var errorInfo;

      args.push(bid.TestHelpers.unexpectedSuccess, function onFailure(info) {
        ok(true, "XHR failure should never pass");
        ok(info.network.url, "url is in network info");
        ok(info.network.type, "request type is in network info");
        equal(info.network.textStatus, "errorStatus", "textStatus is in network info");
        equal(info.network.errorThrown, "errorThrown", "errorThrown is in response info");

        start();
      });

        transport.useResult("ajaxError");
Shane Tomlinson's avatar
Shane Tomlinson committed
      }

      cb && cb.apply(null, args);
    },

    /**
     * Generate a long string
     */
    generateString: function(length) {
      var str = "";
      for(var i = 0; i < length; i++) {
        str += (i % 10);
      }
      return str;
    testKeysInObject: function(objToTest, expected, msg) {
      if (!objToTest) ok(false, "missing objToTest");
      if (!expected) ok(false, "missing objToTest");
        ok(key in objToTest, msg || ("object contains " + key));
Austin King's avatar
Austin King committed
    },

    testObjectValuesEqual: function(objToTest, expected, msg) {
      if (!objToTest) ok(false, "missing objToTest");
      if (!expected) ok(false, "missing objToTest");

        deepEqual(objToTest[key], expected[key], key + " set to: " + expected[key] + (msg ? " - " + msg : ""));
    testUndefined: function(toTest, msg) {
      equal(typeof toTest, "undefined", msg || "object is undefined");
    },

    testNotUndefined: function(toTest, msg) {
      notEqual(typeof toTest, "undefined", msg || "object is defined");
    testVisible: function(selector, msg) {
      ok($(selector).is(":visible"), msg || selector + " is visible");
    },

    testNotVisible: function(selector, msg) {
      equal($(selector).is(":visible"), false, msg || selector + " is not visible");
    testHasClass: function(selector, className, msg) {
      ok($(selector).hasClass(className),
          msg || (selector + " has className " + className));
    },

    testNotHasClass: function(selector, className, msg) {
      ok(!$(selector).hasClass(className),
          msg || (selector + " does not have className " + className));
    },

    testElementExists: function(selector, msg) {
      ok($(selector).length, msg || ("element '" + selector + "' exists"));
    testElementDoesNotExist: function(selector, msg) {
      ok(!$(selector).length, msg || ("element '" + selector + "' does not exist"));
    testRPTosPPShown: function(msg) {
      TestHelpers.testHasClass("body", "rptospp", msg || "RP TOS/PP shown");
    },

    testRPTosPPNotShown: function(msg) {
      TestHelpers.testNotHasClass("body", "rptospp", msg || "RP TOS/PP not shown");
    },

    testElementChecked: function(selector, msg) {
      equal($(selector).is(":checked"), true, msg || selector + " is checked");
    },

    testElementNotChecked: function(selector, msg) {
      equal($(selector).is(":checked"), false, msg || selector + " is not checked");
    },

    testElementFocused: function(selector, msg) {
      var focusedEl = $(":focus");

        ok(true, msg || selector + " is focused");
      }
      else {
        // In some environments such as PhantomJS, input elements cannot be
        // checked for focus.  Make a temporary input element which we can
        // check to see if it is possible to focus. If it is possible, this is
        // a failure.  If it is not possible, print a message and continue.
        // Remove the element when complete.
        var input = $("<input type='radio' />").appendTo("body").focus();
        if (input.is(":focus")) {
          ok(false, msg || selector + " is focused");
          // refocus the original input element.
          if (focusedEl.length) $(focusedEl).focus();
        }
        else {
          window.console && console.log("currently unable to focus elements, focus check skipped - try focusing the unit test page");
        }
        input.remove();
      }
    testEmailMarkedVerified: function(email, msg) {
      var emailInfo = storage.getEmail(email);
      equal(emailInfo && emailInfo.verified, true,
        "verified bit set for " + email);
    },

    testDocumentRedirected: function(doc, expectedHref, msg) {
      equal(doc.location, expectedHref, msg || "document redirected to " + expectedHref);
    },

    testDocumentNotRedirected: function(doc, msg) {
      equal(doc.location.href, document.location.href, msg || "document not redirected");