Newer
Older
/*jshint browser: true laxbreak: true, expr: true */
/*global BrowserID: true, ok: true, equal: true, start: true, deepEqual: true, notEqual: true */
Shane Tomlinson
committed
/* 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/. */
Shane Tomlinson
committed
BrowserID.TestHelpers = (function() {
"use strict";
var bid = BrowserID,
mediator = bid.Mediator,
network = bid.Network,
storage = bid.Storage,
xhr = bid.XHR,
transport = bid.Mocks.xhr,
provisioning = bid.Mocks.Provisioning,
screens = bid.Screens,
Shane Tomlinson
committed
registrations = [],
Lloyd Hilaiel
committed
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);
}
}
Shane Tomlinson
committed
var TestHelpers = {
XHR_TIME_UNTIL_DELAY: 100,
setup: function() {
unregisterAll();
mediator.reset();
xhr.init({
transport: transport,
Shane Tomlinson
committed
time_until_delay: TestHelpers.XHR_TIME_UNTIL_DELAY
});
transport.setDelay(0);
transport.setContextInfo("auth_level", undefined);
transport.setContextInfo("cookies_enabled", true);
transport.useResult("valid");
Shane Tomlinson
committed
network.init({ forceCookieStatus: undefined });
Shane Tomlinson
committed
$("body").stop().show();
$("body")[0].className = "";
$(".error").removeClass("error");
$("#error").hide();
$(".notification").stop().hide();
screens.wait.hide();
screens.error.hide();
screens.delay.hide();
provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
Shane Tomlinson
committed
user.reset();
user.init({
provisioning: provisioning
});
user.setOrigin(testOrigin);
Shane Tomlinson
committed
},
teardown: function() {
unregisterAll();
mediator.reset();
xhr.init({
transport: $,
Shane Tomlinson
committed
time_until_delay: 10 * 1000
});
network.init();
screens.wait.hide();
screens.error.hide();
screens.delay.hide();
provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
testOrigin: testOrigin,
register: register,
Shane Tomlinson
committed
isTriggered: function(message) {
return message in calls;
Shane Tomlinson
committed
},
Shane Tomlinson
committed
testTriggered: function(message, expectedFields) {
ok(message in calls, message + " was triggered");
if (expectedFields) this.testObjectValuesEqual(calls[message], expectedFields);
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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;
},
Shane Tomlinson
committed
testErrorVisible: function() {
Shane Tomlinson
committed
equal(TestHelpers.errorVisible(), true, "error screen is visible");
Shane Tomlinson
committed
Shane Tomlinson
committed
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");
},
Shane Tomlinson
committed
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();
},
expectedXHRFailure: function() {
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");
},
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();
});
Shane Tomlinson
committed
if(transport.responseName === "valid") {
transport.useResult("ajaxError");
Shane Tomlinson
committed
},
/**
* Generate a long string
*/
generateString: function(length) {
var str = "";
for(var i = 0; i < length; i++) {
str += (i % 10);
}
return str;
Shane Tomlinson
committed
},
testKeysInObject: function(objToTest, expected, msg) {
if (!objToTest) ok(false, "missing objToTest");
if (!expected) ok(false, "missing objToTest");
Shane Tomlinson
committed
Shane Tomlinson
committed
for(var i=0, key; key=expected[i]; ++i) {
ok(key in objToTest, msg || ("object contains " + key));
Shane Tomlinson
committed
}
Shane Tomlinson
committed
testObjectValuesEqual: function(objToTest, expected, msg) {
if (!objToTest) ok(false, "missing objToTest");
if (!expected) ok(false, "missing objToTest");
Shane Tomlinson
committed
for(var key in expected) {
deepEqual(objToTest[key], expected[key], key + " set to: " + expected[key] + (msg ? " - " + msg : ""));
Shane Tomlinson
committed
}
},
Shane Tomlinson
committed
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 + " should be visible");
Shane Tomlinson
committed
},
Shane Tomlinson
committed
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"));
Shane Tomlinson
committed
Shane Tomlinson
committed
testElementDoesNotExist: function(selector, msg) {
ok(!$(selector).length, msg || ("element '" + selector + "' does not exist"));
Shane Tomlinson
committed
},
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");
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
},
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");
if (focusedEl.is(selector)) {
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='text' />").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();
}
},
Shane Tomlinson
committed
testEmailMarkedVerified: function(email, msg) {
var emailInfo = storage.getEmail(email);
equal(emailInfo && emailInfo.verified, true,
"verified bit set for " + email);
Shane Tomlinson
committed
return TestHelpers;