drop django-qunit as we're not using it anymore

This commit is contained in:
Mathieu Agopian 2014-04-22 13:06:29 +02:00
Родитель d4ccc97030
Коммит 728cedfc38
37 изменённых файлов: 0 добавлений и 5642 удалений

Просмотреть файл

@ -9,7 +9,6 @@ INSTALLED_APPS += (
'debug_toolbar',
'django_extensions',
'fixture_magic',
'django_qunit',
)
# You want one of the caching backends. Dummy won't do any caching, locmem is

Просмотреть файл

@ -50,5 +50,3 @@ JavaScript
// ...
}
});
- Write :ref:`JavaScript tests <javascript-testing>` whenever possible.

Просмотреть файл

@ -117,68 +117,9 @@ need to recompile the .mo files manually, for example::
msgfmt --check-format -o django.mo django.po
.. _`javascript-testing`:
API Tests
---------
To run all Marketplace API tests, pass an additional `--config` flag to the test
runner::
./manage.py test --config=mkt/api/tests/nose.cfg
If adding new test modules related to the API, ensure that you add them to the
list at `mkt/api/tests/nose.cfg`.
JavaScript Tests
----------------
Frontend JavaScript is currently tested with QUnit_, a simple set of
functions for test setup/teardown and assertions.
Running JavaScript Tests
~~~~~~~~~~~~~~~~~~~~~~~~
You can run the tests a few different ways but during development you
probably want to run them in a web browser by opening this page:
http://127.0.0.1:8000/en-US/firefox/qunit/
Before you can load that page, you'll need to adjust your settings_local.py
file so it includes django-qunit:
.. code-block:: python
INSTALLED_APPS += (
# ...
'django_qunit',
)
Writing JavaScript Tests
~~~~~~~~~~~~~~~~~~~~~~~~
QUnit_ tests for the HTML page above are discovered automatically. Just add
some_test.js to ``media/js/zamboni/tests/`` and it will run in the suite. If
you need to include a library file to test against, edit
``media/js/zamboni/tests/suite.json``.
QUnit_ has some good examples for writing tests. Here are a few
additional tips:
* Any HTML required for your test should go in a sandbox using
``tests.createSandbox('#your-template')``.
See js/zamboni/tests.js for details.
* To make a useful test based on an actual production template, you can create
a snippet and include that in ``templates/qunit.html`` assigned to its own
div. During test setup, reference the div in createSandbox()
* You can use `$.mockjax`_ to test how your code handles server responses,
errors, and timeouts.
.. _`Django's Unit Testing`: http://docs.djangoproject.com/en/dev/topics/testing
.. _`Selenium repository`: https://github.com/mozilla/Addon-Tests/
.. _`the docs`: http://docs.djangoproject.com/en/dev/topics/testing#id1
.. _Qunit: http://docs.jquery.com/Qunit
.. _`$.mockjax`: http://enterprisejquery.com/2010/07/mock-your-ajax-requests-with-mockjax-for-rapid-development/
.. _mock: http://pypi.python.org/pypi/mock
.. _`nose-blockage`: https://github.com/andymckay/nose-blockage

Просмотреть файл

@ -1297,9 +1297,6 @@ PERF_THRESHOLD = 25
REDIS_BACKENDS = {'master': 'redis://localhost:6379?socket_timeout=0.5'}
# Directory of JavaScript test files for django_qunit to run
QUNIT_TEST_DIRECTORY = os.path.join(MEDIA_ROOT, 'js', 'zamboni', 'tests')
# Full path or executable path (relative to $PATH) of the spidermonkey js
# binary. It must be a version compatible with amo-validator
SPIDERMONKEY = None

Просмотреть файл

@ -179,45 +179,6 @@ urlpatterns += patterns('piston.authentication.oauth.views',
name='oauth.access_token'),
)
if 'django_qunit' in settings.INSTALLED_APPS:
def _zamboni_qunit(request, path, template):
from time import time
import django_qunit.views
import jingo
import mock
# Patch `js` so that CI gets cache-busted JS with TEMPLATE_DEBUG=True.
# (This will be fixed in `jingo-minify` with bug 717094.)
from jingo_minify.helpers import _build_html
import jinja2
def js(bundle, defer=False, async=False):
items = settings.MINIFY_BUNDLES['js'][bundle]
attrs = ['src="%s?v=%s"' % ('%s', time())]
if defer:
attrs.append('defer')
if async:
attrs.append('async')
string = '<script %s></script>' % ' '.join(attrs)
return _build_html(items, string)
ctx = django_qunit.views.get_suite_context(request, path)
ctx.update(timestamp=time(), Mock=mock.Mock, js=js)
response = render(request, template, ctx)
# This allows another site to embed the QUnit suite
# in an iframe (for CI).
response['x-frame-options'] = ''
return response
def zamboni_qunit(request, path):
return _zamboni_qunit(request, path, 'qunit/qunit.html')
urlpatterns += patterns('',
url(r'^qunit/(?P<path>.*)', zamboni_qunit),
url(r'^_qunit/', include('django_qunit.urls')),
)
if settings.TEMPLATE_DEBUG:
# Remove leading and trailing slashes so the regex matches.
media_url = settings.MEDIA_URL.lstrip('/').rstrip('/')

Просмотреть файл

@ -1,132 +0,0 @@
//
// Adapter for JS TestNet
// https://github.com/kumar303/jstestnet
//
// Be sure this file is loaded *after* qunit/testrunner.js or whatever else
// you're using
(function() {
var canPost = false;
try {
canPost = !!window.top.postMessage;
} catch(e){}
if (!canPost) {
return;
}
function postMsg(data) {
var msg = '';
for (var k in data) {
if (msg.length > 0) {
msg += '&';
}
msg += k + '=' + encodeURI(data[k]);
}
window.top.postMessage(msg, '*');
}
window.onerror = function(error, url, lineNumber) {
var msg = {
action: 'log',
result: false, // failure
message: 'Exception: ' + error.toString() + ' at ' + url + ':' + lineNumber,
stacktrace: (typeof printStackTrace !== 'undefined') ? printStackTrace({e: error}): null
};
if (typeof console !== 'undefined') {
// Get notified of exceptions during local development.
console.error('Exception:');
console.log(error);
}
postMsg(msg);
};
// QUnit (jQuery)
// http://docs.jquery.com/QUnit
if ( typeof QUnit !== "undefined" ) {
QUnit.begin = function() {
postMsg({
action: 'hello',
user_agent: navigator.userAgent
});
};
QUnit.done = function(failures, total) {
// // Clean up the HTML (remove any un-needed test markup)
// $("nothiddendiv").remove();
// $("loadediframe").remove();
// $("dl").remove();
// $("main").remove();
//
// // Show any collapsed results
// $('ol').show();
postMsg({
action: 'done',
failures: failures,
total: total
});
};
QUnit.log = function(result, message, details) {
// Strip out html:
message = message.replace(/&amp;/g, '&');
message = message.replace(/&gt;/g, '>');
message = message.replace(/&lt;/g, '<');
message = message.replace(/<[^>]+>/g, '');
var msg = {
action: 'log',
result: result,
message: message,
stacktrace: null
};
if (details) {
if (typeof(details.source) !== 'undefined') {
msg.stacktrace = details.source;
}
if (typeof(details.expected) !== 'undefined') {
msg.message += '; Expected: "' + details.expected + '"';
}
if (typeof(details.actual) !== 'undefined') {
msg.message += '; Actual: "' + details.actual + '"';
}
}
postMsg(msg);
};
QUnit.moduleStart = function(name) {
postMsg({
action: 'set_module',
name: name
});
};
QUnit.testStart = function(name) {
postMsg({
action: 'set_test',
name: name
});
};
// window.TestSwarm.serialize = function(){
// // Clean up the HTML (remove any un-needed test markup)
// remove("nothiddendiv");
// remove("loadediframe");
// remove("dl");
// remove("main");
//
// // Show any collapsed results
// var ol = document.getElementsByTagName("ol");
// for ( var i = 0; i < ol.length; i++ ) {
// ol[i].style.display = "block";
// }
//
// return trimSerialize();
// };
} else {
throw new Error("Cannot adapt to jstestnet: Unknown test runner");
}
})();

Просмотреть файл

@ -1,167 +0,0 @@
/*
Utilities for testing jQuery-based JavaScript code.
*/
tests = {};
tests.waitFor = function(checkCondition, config) {
/*
Wait for a condition before doing anything else.
Good for making async tests fast on fast machines.
Use it like this::
tests.waitFor(function() {
return (thing == 'done);
}).thenDo(function() {
equals(1,1);
ok(stuff());
});
You can pass in a config object as the second argument
with these possible attributes:
**config.interval**
milliseconds to wait between polling condition
**config.timeout**
milliseconds to wait before giving up on condition
*/
if (typeof(config) === 'undefined') {
config = {};
}
var interval = config.interval || 20,
timeout = config.timeout || 1000,
run,
runWhenReady,
timeSpent = 0;
run = function() {
if (timeSpent > timeout) {
var cond = checkCondition.toString()
ok(false, "Spent too long waiting for: " + cond);
start();
}
timeSpent += interval;
var ready = checkCondition();
if (!ready) {
setTimeout(run, interval);
} else {
if (typeof runWhenReady === 'function') {
runWhenReady();
}
}
};
setTimeout(run, interval);
return {
thenDo: function(fn) {
runWhenReady = fn;
}
}
};
tests._sbCounter = 0;
tests.createSandbox = function(tmpl) {
/*
Returns a jQuery object for a temporary, unique div filled with html
from a template.
**tmpl**
An optional jQuery locator from which to copy html. This would
typically be the ID of a div in your test runner HTML (e.g. qunit.html)
Example::
module('Group of tests', {
setup: function() {
this.sandbox = tests.createSandbox('#foobar-template');
},
teardown: function() {
this.sandbox.remove();
}
});
test('some test', function() {
this.sandbox.append('...');
});
*/
tests._sbCounter++;
var sb = $('<div id="sandbox-'+tests._sbCounter.toString()+'"></div>');
if (tmpl) {
sb.append($(tmpl).html());
}
$('#sandbox').append(sb);
return sb;
};
tests.StubOb = function(Orig, overrides) {
/*
Returns a class-like replacement for Orig.
**Orig**
object you want to replace.
**overrides**
object containing properties to override in the original.
All properties in the overrides object will replace those of Orig's
prototype when you create an instance of the class. This is useful
for stubbing out certain methods. For example::
z.FileData = tests.StubOb(z.FormData, {
send: function() {}
});
This allows the creation of a FormData object that behaves just like
the original except that send() does not actually post data during
a test::
var fileData = new z.FileData();
fileData.send(); // does nothing
Be sure to assign the original class back when you're done testing.
*/
return function() {
var ob = {}
Orig.apply(ob, this.arguments);
for (k in overrides) {
ob[k] = overrides[k];
}
return ob;
}
};
tests.hasClass = function($sel, cls) {
/*
Asserts that jQuery selector $sel has CSS class cls.
Otherwise, an instructive error is raised.
*/
equals($sel.hasClass(cls), true,
'Expecting ' + cls + ', got: ' + $sel.attr('class'));
}
tests.lacksClass = function($sel, cls) {
/*
Asserts that jQuery selector $sel does not have CSS class cls.
Otherwise, an instructive error is raised.
*/
equals($sel.hasClass(cls), false,
'Should not have ' + cls + ', got: ' + $sel.attr('class'));
};
tests.equalObjects = function(a, b) {
/*
Asserts that two objects are equal by comparing serialized strings.
deepEqual is stupid and flaky.
*/
equal(JSON.stringify(a), JSON.stringify(b));
}
tests.notEqualObjects = function(a, b) {
/*
Asserts that two objects are unequal by comparing serialized strings.
notDeepEqual is stupid and flaky.
*/
notEqual(JSON.stringify(a), JSON.stringify(b));
}

Просмотреть файл

@ -1,39 +0,0 @@
var buttonFixtures = {
setup: function() {
this.sandbox = tests.createSandbox('#buttons');
},
teardown: function() {
this.sandbox.remove();
}
};
module('Buttons', buttonFixtures);
test('Test backup button', function() {
var attr = 'data-version-supported',
current = this.sandbox.find('.install').first();
current_wrapper = this.sandbox.find('.install-shell').first();
backup = this.sandbox.find('.backup-button .install').first();
backup_wrapper = this.sandbox.find('.backup-button').first();
equals(backup_wrapper.hasClass('hidden'), false);
equals(current_wrapper.hasClass('hidden'), true);
current_wrapper.removeClass('hidden');
backup_wrapper.addClass('hidden');
backup.attr(attr, 'false');
current.attr(attr, 'true');
this.sandbox.find('.backup-button').showBackupButton();
equals(backup_wrapper.hasClass('hidden'), true);
equals(current_wrapper.hasClass('hidden'), false);
});
/* Fails in Jenkins 3.6.17, uncomment when we can figure out why.
Does not locally.
test('Test change elements on backup', function() {
$('.backup-button', this.sandbox).showBackupButton();
equals($('.addon-compatible td', this.sandbox).text(), 'Fx 1.0');
equals($('.addon-updated time', this.sandbox).text(), 'today');
});
*/

Просмотреть файл

@ -1,156 +0,0 @@
module('Ajax Cache', {
setup: function() {
this.newItems = {'ajax': [], 'cache': []};
z._AjaxCache = {};
$.mockjaxClear();
$.mockjaxSettings = {
status: 200,
responseTime: 0,
contentType: 'text/json',
dataType: 'json'
};
},
teardown: function() {
$.mockjaxClear();
},
query: function(term, url) {
var self = this,
results = [];
if (url) {
for (var i = 0; i < 10; i++) {
results.push({'id': i, 'url': url});
}
} else {
url = '/cacheMoney';
results = [
{'id': 1, 'url': 'gkoberger.net'},
{'id': 2, 'url': 'gkoberger.net'},
{'id': 3, 'url': 'gkoberger.net'}
];
}
$.mockjax({
url: url,
responseText: JSON.stringify(results),
status: 200,
responseTime: 0
});
var self = this;
this.ajaxCalled = false;
this.cacheCalled = false;
return {
url: url,
data: {'q': term},
ajaxSuccess: function(data, items) {
self.newItems['ajax'].push(items);
self.ajaxCalled = true;
},
cacheSuccess: function(data, items) {
self.newItems['cache'].push(items);
self.cacheCalled = true;
}
};
},
is_ajax: function() {
equal(this.ajaxCalled, true);
equal(this.cacheCalled, false);
},
is_cache: function() {
equal(this.ajaxCalled, false);
equal(this.cacheCalled, true);
}
});
asyncTest('New request', function() {
var self = this;
$.ajaxCache(self.query('some term')).done(function() {
self.is_ajax();
start();
});
});
asyncTest('Identical requests', function() {
var self = this,
request1,
request2;
request1 = $.ajaxCache(self.query('some term')).done(function() {
self.is_ajax();
// This request should be cached.
request2 = $.ajaxCache(self.query('some term'));
self.is_cache();
// Ensure that we returned the correct items.
tests.equalObjects(self.newItems['ajax'], self.newItems['cache']);
// When the request is cached, we don't return an $.ajax request.
equal(request2, undefined);
start();
});
});
asyncTest('Same URLs, unique parameters, same results', function() {
var self = this,
request1,
request2,
request3;
request1 = $.ajaxCache(self.query('some term')).done(function() {
// This is a cached request.
request2 = $.ajaxCache(self.query('some term'));
// This is a request with new parameters but will return same items.
request3 = $.ajaxCache(self.query('new term')).done(function() {
self.is_ajax();
// We return `undefined` when items remain unchanged.
equal(self.newItems['ajax'][1], undefined);
start();
});
});
});
asyncTest('Unique URLs, same parameters, unique results', function() {
var self = this,
request1,
request2;
request1 = $.ajaxCache(self.query('some term', 'poop')).done(function() {
self.is_ajax();
// This is a new request with a different URL.
request2 = $.ajaxCache(self.query('some term', 'crap')).done(function() {
self.is_ajax();
tests.notEqualObjects(self.newItems['ajax'][0],
self.newItems['ajax'][1]);
start();
});
});
});
asyncTest('Unique URLs, unique parameters, unique results', function() {
var self = this,
request1,
request2;
request1 = $.ajaxCache(self.query('some term', 'poop')).done(function() {
self.is_ajax();
// This is a new request with a different URL and different parameters.
request2 = $.ajaxCache(self.query('diff term', 'crap')).done(function() {
self.is_ajax();
tests.notEqualObjects(self.newItems['ajax'][0],
self.newItems['ajax'][1]);
start();
});
});
});

Просмотреть файл

@ -1,102 +0,0 @@
var runtimePitchFixture = {
setup: function(installed, seen_pitch, not_firefox) {
this.sandbox = tests.createSandbox('#balloons');
this.visitor = z.Storage('visitor');
this._firefox = z.browser.firefox;
this._key = 'seen_appruntime_pitch';
this._app_runtime = z.capabilities.app_runtime;
this._seen_pitch = this.visitor.get(this._key);
// The style="display: none" is getting destroyed in the sandbox. WTH.
$('#appruntime-pitch', this.sandbox).hide();
// Mock whether Firefox is installed.
z.browser.firefox = !not_firefox;
// Mock whether App Runtime extension is installed.
z.capabilities.app_runtime = installed;
// Mock whether pitch was dismissed.
if (seen_pitch) {
this.visitor.set(this._key, '1');
} else {
this.visitor.remove(this._key);
}
initBanners(this.sandbox);
},
teardown: function() {
z.browser.firefox = this._firefox;
z.capabilities.app_runtime = this._app_runtime;
this.visitor.set(this._key, this._seen_pitch);
this.sandbox.remove();
},
check: function(show_pitch) {
var self = this,
$balloon = $('#appruntime-pitch', self.sandbox);
if (show_pitch) {
equal($balloon.is(':visible'), true);
$.when($balloon.find('.close').trigger('click')).done(function() {
equal(self.visitor.get(self._key), '1');
});
} else {
equal($balloon.is(':hidden'), true);
}
}
};
module('App Runtime installed', $.extend({}, runtimePitchFixture, {
setup: function() {
runtimePitchFixture.setup.call(this, true, false);
}
}));
test('Hide pitch message', function() {
this.check(false);
});
module('App Runtime installed (dismissed)', $.extend({}, runtimePitchFixture, {
setup: function() {
// This could happen when the user first dismissed the pitch message
// and then installed the extension.
runtimePitchFixture.setup.call(this, true, true);
}
}));
test('Hide pitch message', function() {
this.check(false);
});
// This fails on jenkins for some reason, but the code works as expected in
// Firefox. Trust me.
/*
module('App Runtime missing', $.extend({}, runtimePitchFixture, {
setup: function() {
runtimePitchFixture.setup.call(this, false, false);
}
}));
test('Show pitch message', function() {
this.check(true);
});
*/
module('App Runtime missing in non-Firefox', $.extend({}, runtimePitchFixture, {
setup: function() {
runtimePitchFixture.setup.call(this, false, false, true);
}
}));
test('Hide pitch message', function() {
this.check(false);
});
module('App Runtime missing (seen warning)', $.extend({}, runtimePitchFixture, {
setup: function() {
runtimePitchFixture.setup.call(this, false, true);
}
}));
test('Hide pitch message', function() {
this.check(false);
});

Просмотреть файл

@ -1,194 +0,0 @@
$(document).ready(function(){
module('apps errors', {
setup: function() {
this.sandbox = tests.createSandbox('#apps-error-msg');
$('.modal', this.sandbox).hide();
},
teardown: function() {
this.sandbox.remove();
},
installAppWithError: function(manifestUrl, errorOb, errModalCallback) {
var sb = this.sandbox,
nav = {};
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
error(errorOb);
}
};
if (!errModalCallback) {
errModalCallback = function() {
// False tells the modal code not to execute all the dom
// re-positioning for rendering. Otherwise this makes
// verifying the sandbox hard.
return false;
};
}
apps.install(manifestUrl, {domContext: sb,
navigator: nav,
errModalCallback: errModalCallback});
}
});
asyncTest('test permission error', function() {
var sb = this.sandbox;
$(sb).one('error_shown.apps', function() {
equals($('.apps-error-msg h2', sb).text(),
'App installation not allowed.');
equals($('.apps-error-msg p', sb).text(), 'detailed message');
start();
});
this.installAppWithError('http://nice.com/nice.webapp',
{code: 'permissionDenied',
message: "detailed message"});
});
test('test user canceled', function() {
var sb = this.sandbox,
callback;
callback = function() {
ok(false, 'dialog should not be shown when a user cancels install');
return false;
};
this.installAppWithError('http://nice.com/nice.webapp',
{code: 'denied',
message: 'user canceled installation'},
callback);
});
asyncTest('test unexpected error', function() {
var sb = this.sandbox;
$(sb).one('error_shown.apps', function() {
equals($('.apps-error-msg h2', sb).text(),
'Install failed. Please try again later.');
equals($('.apps-error-msg p', sb).text(), 'surprise');
start();
});
this.installAppWithError('http://nice.com/nice.webapp', {code: 'bogus',
message: "surprise"});
});
test('test successful app install', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {}
};
callback = function() {
ok(false, 'dialog should not be shown on successful app install');
return false;
};
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
errModalCallback: callback});
});
asyncTest('test append to visible modal', function() {
var $sb = $(this.sandbox);
// Simulate a popup:
$sb.append('<div class="existing modal"><div class="modal-inside"></div></div>');
$sb.one('error_shown.apps', function() {
equals($('.existing h2', $sb).text(),
'App installation not allowed.');
equals($('.existing p', $sb).text(),
'detailed message');
start();
});
this.installAppWithError('http://nice.com/nice.webapp',
{code: 'permissionDenied',
message: "detailed message"});
});
module('apps as wrapper', {
setup: function() {
this.sandbox = tests.createSandbox('#apps-error-msg');
$('.modal', this.sandbox).hide();
},
teardown: function() {
this.sandbox.remove();
}
});
asyncTest('success callback', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
success();
}
};
callback = function() {
ok(true, 'success was called');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
success: callback});
});
asyncTest('install error: system unsupported', function() {
var sb = this.sandbox,
nav = {};
$(sb).one('mobile_error_shown.apps', function() {
equal($('.apps-error-msg h2', sb).text(), 'App installation failed.');
equal($('.apps-error-msg p', sb).text(), 'This system does not support installing apps.');
start();
});
apps.install('http://nice.com/nice.webapp', {domContext: sb, navigator: nav, mobile: true});
});
asyncTest('data', function() {
var sb = this.sandbox,
nav = {},
callback,
dataReceived;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
dataReceived = data;
success();
}
};
callback = function() {
equals(dataReceived.receipt, '<receipt>');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
success: callback,
data: {receipt: '<receipt>'}});
});
asyncTest('error callback', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
error({code: 'someCode', message: 'some message'});
}
};
callback = function(errOb) {
equals(errOb.code, 'someCode');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
errModalCallback: function() { return false; },
error: callback});
});
});

Просмотреть файл

@ -1,182 +0,0 @@
$(document).ready(function(){
module('browserid setup', {
setup: function() {
$(window).undelegate('.browserid-login', 'click');
this.sandbox = tests.createSandbox('#browserid-test');
this.originalGVE = gotVerifiedEmail;
this.originalID = navigator.id;
var that = this;
gotVerifiedEmail = function(x, y){
that.assertion = x;
that.to = y;
};
},
teardown: function() {
gotVerifiedEmail = this.originalGVE;
navigator.id = this.originaID;
this.sandbox.remove();
}
});
test('Setup with redirect', function() {
var win = {
'location': {'href': '/users/login?to=/en-US/firefox/'}
};
navigator.id = {
'getVerifiedEmail': function (f) {
f('fake-assertion');
}
};
initBrowserID(win, this.sandbox);
$('.browserid-login', this.sandbox).eq(0).click();
equal(this.to, '/en-US/firefox/');
equal(this.assertion, 'fake-assertion');
});
test('Setup with absolute redirect', function() {
var win = {
'location': {'href': 'http://evilsite.com/badnews/'}
};
navigator.id = {
'getVerifiedEmail': function (f) {
f('fake-assertion');
}
};
initBrowserID(win, this.sandbox);
$('.browserid-login').click();
equal(this.to, '/');
equal(this.assertion, 'fake-assertion');
});
test('Setup with no redirect', function() {
var win = {
'location': {'href': '/users/login'}
};
navigator.id = {
'getVerifiedEmail': function (f) {
f('fake-assertion');
}
};
initBrowserID(win, this.sandbox);
$('.browserid-login').click();
equal(this.to, '/');
equal(this.assertion, 'fake-assertion');
});
test('Setup with no redirect from non login page', function() {
var win = {
'location': {'href': '/users/test'}
};
navigator.id = {
'getVerifiedEmail': function (f) {
f('fake-assertion');
}
};
initBrowserID(win, this.sandbox);
$('.browserid-login').click();
equal(this.to, '/users/test');
equal(this.assertion, 'fake-assertion');
});
module('browserid login', {
setup: function() {
this.origRedirect = browserIDRedirect;
this.sandbox = tests.createSandbox('#browserid-test');
},
teardown: function() {
this.sandbox.remove();
browserIDRedirect = this.origRedirect;
}
});
asyncTest('Login failure (error from server)', function() {
var sandbox = this.sandbox;
$('.browserid-login', sandbox).attr('data-url', '/browserid-login-fail');
equal($('.primary .notification-box', sandbox).length, 0);
browserIDRedirect = function() {};
var i = $.mockjax({url: '/browserid-login-fail',
responseText: '',
status: 401});
gotVerifiedEmail('browserid-assertion', '/', sandbox).always(
function(ex) {
equal($('.primary .notification-box h2', sandbox).text().indexOf(
"BrowserID login failed. Maybe you don't have an account"
+ ' under that email address?'), 0);
$('.primary .notification-box', sandbox).remove();
$.mockjaxClear(i);
start();
});
});
asyncTest('Login failure (message from server)', function() {
var TESTMSG = 'Example error message';
var sandbox = this.sandbox;
$('.browserid-login', sandbox).attr('data-url', '/browserid-login-fail');
equal($('.primary .notification-box', sandbox).length, 0);
browserIDRedirect = function() { };
var i = $.mockjax({url: '/browserid-login-fail',
responseText: TESTMSG,
status: 401});
gotVerifiedEmail('browserid-assertion', '/', sandbox).fail(
function() {
equal($('.primary .notification-box h2', sandbox).text().indexOf(
TESTMSG), 0);
$('.primary .notification-box', sandbox).remove();
$.mockjaxClear(i);
start();
});
});
test('Login cancellation', function() {
var sandbox = this.sandbox;
$('.browserid-login', sandbox).attr('data-url', '/browserid-login-cancel');
var i = $.mockjax({url: '/browserid-login-cancel',
response: function () {
ok(false, 'XHR call made when user cancelled');
}});
equal(gotVerifiedEmail(null, '/', sandbox), null);
equal($('.primary .notification-box', sandbox).length, 0);
$.mockjaxClear(i);
});
asyncTest('Login success', function() {
var ajaxCalled = false,
sandbox = this.sandbox;
$('.browserid-login', sandbox).attr('data-url', '/browserid-login-success');
equal($('.primary .notification-box', sandbox).length, 0);
browserIDRedirect = function(to) {
return function() { ajaxCalled = true; };
};
var i = $.mockjax({url: '/browserid-login-success',
responseText: '',
status: 200});
gotVerifiedEmail('browserid-assertion', '/', sandbox).done(
function() {
ok(ajaxCalled);
$.mockjaxClear(i);
start();
});
});
asyncTest('Admin login failure', function() {
var sandbox = this.sandbox;
$('.browserid-login', sandbox).attr('data-url', '/browserid-login-fail');
equal($('.primary .notification-box', sandbox).length, 0);
browserIDRedirect = function() {};
var i = $.mockjax({url: '/browserid-login-fail',
responseText: '',
status: 400});
gotVerifiedEmail('browserid-assertion', '/', sandbox).fail(
function() {
equal($('.primary .notification-box h2', sandbox).text(),
'Admins and editors must provide a password'
+ ' to log in.');
$('.primary .notification-box', sandbox).remove();
$.mockjaxClear(i);
start();
});
});
});

Просмотреть файл

@ -1,570 +0,0 @@
$(document).ready(function(){
var catFixture = {
setup: function() {
this.sandbox = tests.createSandbox('#addon-cats');
initCatFields(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
};
module('initCatFields', catFixture);
test('Default with initial categories', function() {
var scope = $("#addon-cats-fx", this.sandbox);
var checkedChoices = $("input:checked", scope);
equals(checkedChoices.length, 2);
equals(checkedChoices[0].id, "id_form-0-categories_1");
equals(checkedChoices[1].id, "id_form-0-categories_2");
// 2 categories are selected, the other category should be disabled.
var max = scope.parent("div").attr("data-max-categories");
equals(parseInt(max, 10), 2);
var disabledChoices = $("input:disabled", this.sandbox);
equals(disabledChoices.length, 1);
equals(disabledChoices[0].id, "id_form-0-categories_0");
});
test('Default without initial categories', function() {
equals($("#addon-cats-tb input:checked", this.sandbox).length, 0);
});
module('addonUploaded', {
setup: function() {
this._FormData = z.FormData;
this.FormDataStub = tests.StubOb(z.FormData, {
send: function() {}
});
z.FormData = this.FormDataStub;
this.sandbox = tests.createSandbox('#file-upload-template');
$.fx.off = true;
this.uploader = $('#upload-file-input', this.sandbox).addonUploader();
this.el = $('#upload-file-input', this.sandbox)[0];
this.file = {
size: 200,
name: 'some-addon.xpi'
};
this.el.files = [this.file];
$(this.el).trigger('change');
// sets all animation durations to 0
$.fx.off = true;
},
teardown: function() {
$.fx.off = false;
this.sandbox.remove();
z.FormData = this._FormData;
$.fx.off = false;
}
});
test('JSON error', function() {
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'},
{'error': "Traceback (most recent call last): ...NameError"}]);
ok($('#upload-status-bar', this.sandbox).hasClass('bar-fail'));
equals($('#upload_errors', this.sandbox).text(),
'Unexpected server error while validating.')
});
test('Too many messages', function() {
var results = {
validation: {
"errors": 7,
"success": false,
"warnings": 0,
"ending_tier": 3,
"messages": [{
"message": "Invalid maximum version number",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
},
{
"message": "Missing translation file",
"type": "error"
}],
"rejected": false,
"detected_type": "extension",
"notices": 0,
},
error: null,
full_report_url: '/full-report'
};
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'}, results]);
equals($('#upload-status-results ul li', this.sandbox).length, 6);
equals($('#upload-status-results ul li:eq(5)', this.sandbox).text(),
'…and 2 more');
});
test('form errors are cleared', function() {
var fxt = this;
// Simulate django form errors from the POST
this.sandbox.find('form').prepend(
'<ul class="errorlist"><li>Duplicate UUID found.</li></ul>');
$(this.el).trigger("upload_start", [{name: 'somefile.txt'}]);
equals($('ul.errorlist', this.sandbox).length, 0);
});
test('Notices count as warnings', function() {
var results = {
validation: {
"warnings": 4,
"notices": 4,
"errors": 0,
"success": true,
"ending_tier": 3,
"rejected": false,
"detected_type": "extension"
},
error: null,
full_report_url: '/full-report',
platforms_to_exclude: []
};
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'}, results]);
equals($('##upload-status-results strong', this.sandbox).text(),
'Your add-on passed validation with no errors and 8 warnings.');
});
test('HTML in errors', function() {
var results = {
validation: {
"errors": 1,
"success": false,
"warnings": 0,
"ending_tier": 3,
"messages": [{
// TODO(Kumar) when validator is no longer escaped, change this
"message": "invalid properties in the install.rdf like &lt;em:id&gt;",
"type": "error"
}],
"rejected": false,
"detected_type": "extension",
"notices": 0,
},
error: null,
full_report_url: '/full-report'
};
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'}, results]);
ok($('#upload-status-bar', this.sandbox).hasClass('bar-fail'));
equals($('#upload_errors', this.sandbox).text(),
'invalid properties in the install.rdf like <em:id>')
});
test('HTML in filename (on start)', function() {
$(this.el).trigger("upload_start", [{name: "tester's add-on2.xpi"}]);
equals($('#upload-status-text', this.sandbox).text(),
"Uploading tester's add-on2.xpi");
});
test('HTML in filename (on error)', function() {
var errors = [],
results = {};
$(this.el).trigger("upload_errors",
[{name: "tester's add-on2.xpi"}, errors, results]);
equals($('#upload-status-text', this.sandbox).text(),
"Error with tester's add-on2.xpi");
});
test('HTML in filename (on success)', function() {
$.mockjax({
url: '/poll-for-results-success',
responseText: {
error: ""
},
status: 200
});
var results = {url: '/poll-for-results-success'};
$(this.el).trigger("upload_success",
[{name: "tester's add-on2.xpi"}, results]);
equals($('#upload-status-text', this.sandbox).text(),
"Validating tester's add-on2.xpi");
});
test('400 JSON error', function() {
var xhr = {
readyState: 4,
status: 400,
responseText: JSON.stringify({
"validation": {
"messages": [{"type": "error", "message": "Some form error"}]
}
})
};
this.uploader.trigger('upload_onreadystatechange', [this.file, xhr]);
equals(this.sandbox.find('#upload_errors').text().trim(), 'Some form error');
});
asyncTest('400 JSON error after polling', function() {
var sb = this.sandbox;
$.mockjax({
url: '/poll-for-results',
responseText: {
validation: {
messages: [{tier: 1,
message: "UUID doesn't match add-on.",
"type": "error"}]},
error: ""
},
status: 400
});
this.uploader.trigger('upload_success_results',
[this.file, {validation: '', url: '/poll-for-results'}]);
// It would be nice to stub out setTimeout but that throws permission errors.
tests.waitFor(function() {
return $('#upload_errors', sb).length;
}, {timeout: 2000} ).thenDo(function() {
equals(sb.find('#upload_errors').text().trim(), "UUID doesn't match add-on.");
start();
});
});
test('append form data callback', function() {
var called = false,
self = this;
$('#upload-file-input', this.sandbox).addonUploader({
appendFormData: function(formData) {
called = true;
ok(formData.append);
}
});
$(this.el).trigger('change');
ok(called);
});
test('Unrecognized file type', function() {
var errors;
$(this.el).bind('upload_errors', function(e, file, error_msgs) {
errors = error_msgs;
});
this.file.name = 'somefile.pdf';
$(this.el).trigger('change');
equals(errors[0], "The filetype you uploaded isn't recognized.");
});
module('fileUpload', {
setup: function() {
var fxt = this;
this.sandbox = tests.createSandbox('#file-upload-template');
initUploadControls();
this.uploadFile = window.uploadFile;
this.uploadFileCalled = false;
// stub out the XHR calls:
window.uploadFile = function() {
fxt.uploadFileCalled = true;
return null;
};
},
teardown: function() {
this.sandbox.remove();
window.uploadFile = this.uploadFile;
}
});
module('preview_edit', {
setup: function() {
this.sandbox = tests.createSandbox('#preview-list');
initUploadPreview();
},
teardown: function() {
this.sandbox.remove();
}
});
test('Clicking delete screenshot marks checkbox.', function() {
// $.fx.off sets all animation durations to 0
$.fx.off = true;
$(".edit-previews-text a.remove", this.sandbox).trigger('click');
equals($(".delete input", this.sandbox).attr("checked"), 'checked');
equals($(".preview:visible", this.sandbox).length, 0);
$.fx.off = false;
});
module('addon platform chooser', {
setup: function() {
this.sandbox = tests.createSandbox('#addon-platform-chooser');
},
teardown: function() {
this.sandbox.remove();
},
check: function(sel) {
$(sel, this.sandbox).attr('checked', 'checked').trigger('change');
}
});
test('platforms > ALL', function() {
// Check some platforms:
this.check('input[value="2"]');
this.check('input[value="3"]');
// Check ALL platforms:
this.check('input[value="1"]');
equals($('input[value="2"]', this.sandbox).attr('checked'), undefined);
equals($('input[value="3"]', this.sandbox).attr('checked'), undefined);
});
test('ALL > platforms', function() {
// Check ALL platforms:
this.check('input[value="1"]');
// Check any other platform:
this.check('input[value="2"]');
equals($('input[value="1"]', this.sandbox).attr('checked'), undefined);
});
test('mobile / desktop', function() {
// Check ALL desktop platforms:
this.check('input[value="1"]');
// Check ALL mobile platforms:
this.check('input[value="9"]');
// desktop platforms are still checked:
equals($('input[value="1"]', this.sandbox).attr('checked'), 'checked');
});
test('mobile > ALL', function() {
// Check ALL mobile platforms:
this.check('input[value="9"]');
// Check Android:
this.check('input[value="7"]');
// ALL mobile is no longer checked:
equals($('input[value="9"]', this.sandbox).attr('checked'), undefined);
});
test('ALL > mobile', function() {
// Check Android, Maemo:
this.check('input[value="7"]');
this.check('input[value="8"]');
// Check ALL mobile platforms:
this.check('input[value="9"]');
// Specific platforms are no longer checked:
equals($('input[value="7"]', this.sandbox).attr('checked'), undefined);
equals($('input[value="8"]', this.sandbox).attr('checked'), undefined);
});
// TODO(Kumar) uncomment when bug 706597 is fixed
// module('slugified fields', {
// setup: function() {
// this.sandbox = tests.createSandbox('#slugified-field');
// },
// teardown: function() {
// this.sandbox.remove();
// }
// });
//
// asyncTest('non-customized', function() {
// load_unicode();
// tests.waitFor(function() {
// return z == null || z.unicode_letters;
// }).thenDo(function() {
// $("#id_name").val("password exporter");
// slugify();
// equals($("#id_slug").val(), 'password-exporter');
// $("#id_name").val("password exporter2");
// slugify();
// equals($("#id_slug").val(), 'password-exporter2');
// start();
// });
// });
//
// asyncTest('customized', function() {
// load_unicode();
// tests.waitFor(function() {
// return z == null || z.unicode_letters;
// }).thenDo(function() {
// $("#id_name").val("password exporter");
// slugify();
// equals($("#id_slug").val(), 'password-exporter');
// $("#id_slug").attr("data-customized", 1);
// $("#id_name").val("password exporter2");
// slugify();
// equals($("#id_slug").val(), 'password-exporter');
// start();
// });
// });
module('exclude platforms', {
setup: function() {
this._FormData = z.FormData;
z.FormData = tests.StubOb(z.FormData, {
send: function() {}
});
this.sandbox = tests.createSandbox('#addon-platform-exclusion');
$.fx.off = true;
$('#upload-file-input', this.sandbox).addonUploader();
this.el = $('#upload-file-input', this.sandbox)[0];
this.el.files = [{
size: 200,
name: 'some-addon.xpi'
}];
$(this.el).trigger('change');
},
teardown: function() {
this.sandbox.remove();
z.FormData = this._FormData;
}
});
test('mobile / android', function() {
var sb = this.sandbox;
results = {
validation: {
"errors": 0,
"detected_type": "mobile",
"success": true,
"warnings": 0,
"notices": 0,
"message_tree": {},
"messages": [],
"rejected": false
},
// exclude all but mobile:
platforms_to_exclude: ['1', '2', '3', '5']
};
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'}, results]);
// All desktop platforms disabled:
equal($('.desktop-platforms input:disabled', sb).length, 4);
ok($('.desktop-platforms label:eq(0)', sb).hasClass('platform-disabled'));
ok($('.platform ul.errorlist', sb).length > 0, 'Message shown to user');
// All mobile platforms not disabled:
equal($('.mobile-platforms input:disabled', sb).length, 0);
});
test('existing platforms', function() {
var sb = this.sandbox;
results = {
validation: {
"errors": 0,
"detected_type": "extension",
"success": true,
"warnings": 0,
"notices": 0,
"message_tree": {},
"messages": [],
"rejected": false
},
// exclude one platform as if this version already fulfilled it
platforms_to_exclude: ['2']
};
$(this.el).trigger("upload_success_results",
[{name: 'somefile.txt'}, results]);
equals($('.desktop-platforms input:eq(0)', sb).attr('disabled'), undefined);
equals($('.desktop-platforms input:eq(1)', sb).attr('disabled'), 'disabled');
equals($('.desktop-platforms label:eq(0)', sb).hasClass('platform-disabled'),
false);
});
module('perf-tests', {
setup: function() {
this.sandbox = tests.createSandbox('#file-perf-tests');
initPerfTests(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
});
asyncTest('success', function() {
var $sb = this.sandbox;
$('.start-perf-tests', $sb).attr('href', '/file-perf-stub1');
$.mockjax({
url: '/file-perf-stub1',
responseText: {success: true},
status: 200,
responseTime: 0
});
$('.start-perf-tests', $sb).trigger('click');
tests.waitFor(function() {
return $('.perf-results', $sb).attr('data-got-response') == '1';
}).thenDo(function() {
// TODO(Kumar) add checks for polling
equals($('.perf-results', $sb).text(), 'Waiting for test results...')
start();
});
});
asyncTest('failure', function() {
var $sb = this.sandbox;
$('.start-perf-tests', $sb).attr('href', '/file-perf-stub2');
$.mockjax({
url: '/file-perf-stub2',
responseText: {success: false},
status: 200,
responseTime: 0
});
$('.start-perf-tests', $sb).trigger('click');
tests.waitFor(function() {
return $('.perf-results', $sb).attr('data-got-response') == '1';
}).thenDo(function() {
equals($('.perf-results', $sb).text(), 'Internal Server Error')
start();
});
});
asyncTest('500 error', function() {
var $sb = this.sandbox;
$('.start-perf-tests', $sb).attr('href', '/file-perf-stub3');
$.mockjax({
url: '/file-perf-stub3',
responseText: '',
status: 500,
responseTime: 0
});
$('.start-perf-tests', $sb).trigger('click');
tests.waitFor(function() {
return $('.perf-results', $sb).attr('data-got-response') == '1';
}).thenDo(function() {
equals($('.perf-results', $sb).text(), 'Internal Server Error')
start();
});
});
});

Просмотреть файл

@ -1,138 +0,0 @@
$(document).ready(function(){
var editorFixtures = {
setup: function() {
this.sandbox = tests.createSandbox('#editors-search-form');
},
teardown: function() {
this.sandbox.remove();
},
selectOpt: function(index) {
var doc = this.sandbox;
$('#id_application_id option', doc).eq(index).attr('selected', 'selected');
$('#id_application_id', doc).trigger('change');
}
};
module('editors search form 1', editorFixtures);
asyncTest('select application', function() {
var doc = this.sandbox;
$('#id_application_id', doc).attr('data-url', '/app-ver1.json');
initQueueSearch(doc);
$.mockjax({
url: '/app-ver1.json',
status: 200,
response: function(settings) {
equals(settings.data.application_id, '1');
this.responseText = {
choices: [['', ''],
['4.0b2pre', '4.0b2pre'],
['2.0a1pre', '2.0a1pre'],
['1.0', '1.0']]
};
}
});
this.selectOpt(1);
tests.waitFor(function() {
return ($('#id_max_version option', doc).length > 1);
}).thenDo(function() {
var values = [];
$.each($('#id_max_version option', doc), function(i, e) {
values.push($(e).val());
});
same(values, ["", "4.0b2pre", "2.0a1pre", "1.0"]);
start();
});
});
module('editors search form 2', editorFixtures);
asyncTest('de-select application', function() {
var suite = this,
doc = this.sandbox;
$('#id_application_id', doc).attr('data-url', '/app-ver2.json');
initQueueSearch(doc);
$.mockjax({
url: '/app-ver2.json',
status: 200,
responseText: {choices: [['', ''], ['4.0b2pre', '4.0b2pre']]}
});
suite.selectOpt(1);
tests.waitFor(function() {
return ($('#id_max_version option', doc).length > 1);
}).thenDo(function() {
suite.selectOpt(0);
tests.waitFor(function() {
return ($('#id_max_version option', doc).length == 1);
}).thenDo(function() {
equals($('#id_max_version option', doc).text(),
'Select an application first');
start();
});
});
});
module('editors MOTD', {
setup: function() {
z.Storage().remove('motd_closed');
this.sandbox = tests.createSandbox('#editors-motd-template');
$('.daily-message .close', this.sandbox).hide();
initDailyMessage(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
});
test('is closable', function() {
var doc = this.sandbox;
equals($('.daily-message .close:visible', doc).length, 1);
});
asyncTest('click to close', function() {
var doc = this.sandbox;
$('.daily-message .close', doc).trigger('click');
tests.waitFor(function() {
return $('.daily-message .close:visible', doc).length == 0;
}).thenDo(function() {
ok(true, 'message was closed');
start();
});
});
module('editors MOTD page', {
setup: function() {
this.sandbox = tests.createSandbox('#editors-motd-for-edit-template');
$('.daily-message .close', this.sandbox).hide();
initDailyMessage(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
});
test('not closable', function() {
var doc = this.sandbox;
equals($('.daily-message .close:visible', doc).length, 0);
});
module('editors MOTD after clicking', {
setup: function() {
z.Storage().set('motd_closed', 'This is an announcement');
this.sandbox = tests.createSandbox('#editors-motd-template');
initDailyMessage(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
});
test('message hidden', function() {
var doc = this.sandbox;
equals($('.daily-message .close:visible', doc).length, 0);
});
});

Просмотреть файл

@ -1,25 +0,0 @@
$(document).ready(function(){
var fileViewer = {
setup: function() {
this.sandbox = tests.createSandbox('#files-wrapper');
},
teardown: function() {
this.sandbox.remove();
}
};
module('File viewer', fileViewer);
test('Show leaf', function() {
var nodes = {
$files: this.sandbox.find($('#files'))
};
var viewer = bind_viewer(nodes);
viewer.toggle_leaf(this.sandbox.find('a.directory'));
equal(this.sandbox.find('a.directory').hasClass('open'), true);
equal(this.sandbox.find('ul:hidden').length, 0);
viewer.toggle_leaf(this.sandbox.find('a.directory'));
equal(this.sandbox.find('a.directory').hasClass('open'), false);
equal(this.sandbox.find('ul:hidden').length, 1);
});
});

Просмотреть файл

@ -1,98 +0,0 @@
$(document).ready(function(){
function _inspectHeaders(inspector, url) {
var headersInspected = false,
url = url || '/local-request-for-csrf.json';
$.mockjax({
url: url,
status: 200,
response: function(settings) {
inspector(this.headers);
start();
}
});
$.ajax({
url: url,
type: 'post',
data: 'foo=bar',
success: function(response) {},
error: function(xhr) {
console.log('ajax request Failed');
}
});
}
module('jQuery exists', {
setup: function() {
this.sandbox = tests.createSandbox('#exists');
},
teardown: function() {
this.sandbox.remove();
}
});
test('Element exists', function() {
equals($('.exists', this.sandbox).exists(), true);
});
test('Element does not exist', function() {
equals($('.doesnotexist', this.sandbox).exists(), false);
});
module('CSRF Token from input', {
setup: function() {
this._csrf = $.cookie('csrftoken');
$.cookie('csrftoken', '');
this.sandbox = tests.createSandbox('#csrf-template');
},
teardown: function() {
this.sandbox.remove();
if (this._csrf) {
$.cookie('csrftoken', this._csrf);
}
}
});
asyncTest('header sent', function() {
_inspectHeaders(function(headers) {
equals(headers['X-CSRFToken'], '<csrf-from-input>');
});
});
module('CSRF Token: remote', {
setup: function() {
$.cookie('csrftoken', null);
}
});
// these started failing after upgrading some libs
// asyncTest('CSRF not sent 1', function() {
// _inspectHeaders(function(headers) {
// var htype = typeof headers['X-CSRFToken'];
// equals(htype, 'undefined');
// }, 'http://someserver/hijack1');
// });
//
// asyncTest('CSRF not sent 2', function() {
// _inspectHeaders(function(headers) {
// var htype = typeof headers['X-CSRFToken'];
// equals(htype, 'undefined');
// }, 'https://someserver/hijack2');
// });
//
// asyncTest('CSRF not sent 3', function() {
// _inspectHeaders(function(headers) {
// var htype = typeof headers['X-CSRFToken'];
// equals(htype, 'undefined');
// }, '//someserver/hijack');
// });
//
// asyncTest('CSRF not sent 4', function() {
// _inspectHeaders(function(headers) {
// var htype = typeof headers['X-CSRFToken'];
// equals(htype, 'undefined');
// }, '://someserver/hijack2');
// });
});

Просмотреть файл

@ -1,28 +0,0 @@
$(document).ready(function(){
var hovercardFixture = {
setup: function() {
this.sandbox = tests.createSandbox('#hovercard-grid');
this.grid = listing_grid.call(this.sandbox.find(".listing-grid"));
},
teardown: function() {
this.sandbox.remove();
}
};
module('hovercards', hovercardFixture);
test('paginator exists', function() {
equals($('nav.pager', this.sandbox).length, 1);
});
test('paginator has correct number of pages', function() {
equals($('nav.pager .dot', this.sandbox).length, 3);
});
test('paginator works properly', function() {
this.grid.go(2);
equals($('section:visible', this.sandbox).index(), 2);
});
});

Просмотреть файл

@ -1,263 +0,0 @@
$(document).ready(function() {
var installButtonFixture = {
setup: function(sandboxId) {
this.sandbox = tests.createSandbox(sandboxId);
this.button = $('.button', this.sandbox);
this.expected = {};
},
teardown: function() {
this.sandbox.remove();
},
check: function(expected) {
for (var prop in expected) {
if (expected.hasOwnProperty(prop)) {
equal(this.button.attr(prop), expected[prop]);
}
}
}
};
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button');
}
}));
test('add-on', function() {
// Patch user agent as Firefox 3.6.
var _browserVersion = z.browserVersion;
z.app = 'firefox';
z.browser.firefox = true;
z.browserVersion = '3.6';
z.platform = 'mac';
var installer = $('.install', this.sandbox).installButton();
equal(installer.length, 1);
equal(installer.attr('data-version-supported'), 'true');
equal(installer.find('a.installer').attr('href'), 'http://testurl.com');
_browserVersion = z.browserVersion;
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-warning');
}
}));
test('app, warning, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-eula');
}
}));
test('app, eula, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-premium');
}
}));
test('premium, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = 'http://testurl.com';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-contrib');
}
}));
test('contrib, mobile', function() {
this.expected['data-hash'] = '1337';
this.expected['href'] = 'http://testurl.com';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-purchasable');
}
}));
test('can be purchased, mobile', function() {
this.expected['data-hash'] = '1337';
this.expected['href'] = 'http://testurl.com';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-app-premium');
}
}));
test('app, premium, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-app-contrib');
}
}));
test('app, contrib, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-app-purchasable');
}
}));
test('app, can be purchased, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-mp-warning');
}
}));
test('marketplace, app, warning, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-mp-eula');
}
}));
test('marketplace, app, eula, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = '#';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-mp-premium');
}
}));
test('marketplace, premium, mobile', function() {
this.expected['data-hash'] = undefined;
this.expected['href'] = 'http://testurl.com';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
module('Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#install-button-mp-contrib');
}
}));
test('marketplace, contrib, mobile', function() {
this.expected['data-hash'] = '1337';
this.expected['href'] = 'http://testurl.com';
this.expected['data-realurl'] = undefined;
this.check(this.expected);
});
// All compatible.
module('D2C Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#button-d2c-compatible');
}
}));
test('d2c, is_compatible', function() {
this.expected['class'] = 'button add installer';
this.check(this.expected);
equal($('.extra', this.sandbox).length, 0);
});
// Compatible, but with an override.
module('D2C Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#button-d2c-compatible-override');
}
}));
test('d2c, is_compatible, override', function() {
this.expected['class'] = 'button add concealed';
this.check(this.expected);
equal($('.extra', this.sandbox).length, 1);
equal($('.notavail', this.sandbox).text().substr(0, 13), 'Not available');
equal($('.d2c-reasons-popup ul li', this.sandbox).length, 1);
equal($('.d2c-reasons-popup ul', this.sandbox).html().indexOf('marked this version as incompatible') !== -1, true);
});
// Server side checks are incompatible.
module('D2C Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#button-d2c-not-compatible');
}
}));
test('d2c, is_compatible, older browser', function() {
this.expected['class'] = 'button add concealed';
this.check(this.expected);
equal($('.extra', this.sandbox).length, 1);
equal($('.notavail', this.sandbox).text().substr(0, 13), 'Not available');
});
// Browser version is < the minimum supported app version.
module('D2C Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#button-d2c-older-browser');
}
}));
test('d2c, is_compatible, older browser', function() {
this.expected['class'] = 'button add concealed';
this.check(this.expected);
equal($('.extra', this.sandbox).length, 1);
equal($('.notavail', this.sandbox).text().substr(0, 13), 'Not available');
});
// Max version isn't high enough to support d2c.
module('D2C Install Button', $.extend({}, installButtonFixture, {
setup: function() {
installButtonFixture.setup.call(this, '#button-d2c-old-max');
}
}));
test('d2c, not is_compatible, max version', function() {
this.expected['class'] = 'button add concealed';
this.check(this.expected);
equal($('.d2c-reasons-popup', this.sandbox).length, 0);
equal($('.d2c-reasons-help', this.sandbox).length, 0);
equal($('.notavail', this.sandbox).text().substr(0, 13), 'Not available');
});
});

Просмотреть файл

@ -1,37 +0,0 @@
$(document).ready(function(){
var transFixture = {
setup: function() {
this.sandbox = tests.createSandbox('#l10n-translation');
},
teardown: function() {
this.sandbox.remove();
}
};
module('z.refreshL10n', transFixture);
test('English', function() {
z.refreshL10n('en-us');
equals($('textarea:visible', this.sandbox).text().trim(),
'Firebug integrates with Firefox to put a wealth of ' +
'development tools...');
});
test('Japanese (existing translation)', function() {
z.refreshL10n('ja');
equals($('textarea:visible', this.sandbox).text().trim(),
'Firebug は、Web ページを閲覧中にクリック一つで使える豊富な開発ツールを Firefox' +
' に統合します。あなたはあらゆる');
});
test('Afrikaans (new translation)', function() {
z.refreshL10n('af');
equals($('[lang=af]', this.sandbox).length, 1);
equals($('textarea:visible', this.sandbox).text().trim(),
'Firebug integrates with Firefox to put a wealth of ' +
'development tools...');
equals($('textarea:visible', this.sandbox).hasClass('cloned'), true);
});
});

Просмотреть файл

@ -1,22 +0,0 @@
$(document).ready(function(){
var payments = {
setup: function() {
this.sandbox = tests.createSandbox('#upsell-test');
initPayments(this.sandbox);
},
teardown: function() {
this.sandbox.remove();
}
};
module('Payment form', payments);
test('Upsell addon click', function() {
this.sandbox.find("#id_free").focus();
equal(this.sandbox.find("#id_do_upsell_1").attr("checked"),
"checked");
});
test('Upsell description click', function() {
this.sandbox.find("#id_text").focus();
equal(this.sandbox.find("#id_do_upsell_1").attr("checked"),
"checked");
});
});

Просмотреть файл

@ -1,35 +0,0 @@
$(document).ready(function(){
var password = {
setup: function() {
this.sandbox = tests.createSandbox('#password-strength');
this.$node = this.sandbox.find('input[type=password]');
initStrength(this.$node);
},
teardown: function() {
this.sandbox.remove();
}
};
module('Passwords', password);
test('Length', function() {
this.$node.val('123457890').trigger('blur');
equal(this.$node.parent().find('ul.errorlist li:hidden').exists(), true);
this.$node.val('123').trigger('blur');
equal(this.$node.parent().find('ul.errorlist li:hidden').exists(), false);
});
test('Complexity', function() {
var $strength = this.$node.parent().find('ul.errorlist li.strength progress');
this.$node.val('123').trigger('blur');
equal($strength.attr('value'), 20);
this.$node.val('123abcDEF').trigger('blur');
equal($strength.attr('value'), 60);
this.$node.val('АзәрбајҹанA13').trigger('blur');
equal($strength.attr('value'), 80);
});
});

Просмотреть файл

@ -1,49 +0,0 @@
$(document).ready(function() {
var personaFixture = {
setup: function() {
this.sandbox = tests.createSandbox('#personas');
initLicense();
},
teardown: function() {
this.sandbox.remove();
},
selectRadio: function(name, value) {
var suite = this.sandbox;
$('input[name=' + name + ']', suite).val(value);
$('input[name=' + name + '][value=' + value + ']', suite)
.attr('checked', true).trigger('change');
}
};
module('Personas', personaFixture);
test('License Chooser', function() {
var that = this,
suite = that.sandbox;
function ccTest(values, licenseName, licenseId) {
that.selectRadio('cc-attrib', values[0]);
if (values.length > 1) {
that.selectRadio('cc-noncom', values[1]);
if (values.length > 2) {
that.selectRadio('cc-noderiv', values[2]);
}
}
equals($('#cc-license', suite).text(), licenseName);
equals(parseInt($('#id_license', suite).val()), licenseId);
}
ccTest([0], 'Creative Commons Attribution 3.0', 9);
ccTest([0, 0], 'Creative Commons Attribution 3.0', 9);
ccTest([0, 0, 0], 'Creative Commons Attribution 3.0', 9);
ccTest([0, 0, 0], 'Creative Commons Attribution 3.0', 9);
ccTest([0, 0, 1], 'Creative Commons Attribution-ShareAlike 3.0', 13);
ccTest([0, 0, 2], 'Creative Commons Attribution-NoDerivs 3.0', 12);
ccTest([0, 1, 0], 'Creative Commons Attribution-NonCommercial 3.0', 10);
ccTest([0, 1, 1], 'Creative Commons Attribution-NonCommercial-Share Alike 3.0', 8);
ccTest([0, 1, 2], 'Creative Commons Attribution-NonCommercial-NoDerivs 3.0', 11);
ccTest([1], 'All Rights Reserved', 7);
ccTest([1, 0], 'All Rights Reserved', 7);
ccTest([1, 0, 0], 'All Rights Reserved', 7);
});
});

Просмотреть файл

@ -1,37 +0,0 @@
module('Homepage promos', {
setup: function(hasAppsSupport, hasSeenAppsSupportWarning) {
this.sandbox = tests.createSandbox('#amo-promos');
this.visitor = z.Storage('visitor');
this.KEY = 'amo_home_promo_seen';
this.MAX_SEEN = 5;
this._promo_seen = this.visitor.get(this.KEY);
this.visitor.remove(this.KEY);
hideHomePromo(this.sandbox);
},
teardown: function() {
this.visitor.set(this.KEY, this._promo_seen);
this.sandbox.remove();
},
check: function(showPromo, cnt) {
var $panel = $('#starter', this.sandbox).closest('.panel');
equal($panel.length, showPromo ? 1 : 0);
equal(parseInt(this.visitor.get(this.KEY), 10), cnt || 0);
}
});
test('No promos visible', function() {
$('.panel', this.sandbox).remove('.panel');
initPromos(this.sandbox);
equal($('.slider:hidden', this.sandbox).length, 1);
});
test('Home promo visible', function() {
this.check(true, 1);
});
test('Home promo not visible on 6th visit', function() {
for (var i = 0; i < 5; i++) {
hideHomePromo(this.sandbox);
}
this.check(false, 5);
});

Просмотреть файл

@ -1,108 +0,0 @@
module('Autofill Platform for Search', {
setup: function() {
this._z = $.extend(true, {}, z); // Deep copy `z` so we can patch.
this.sandbox = tests.createSandbox('#search-box');
},
teardown: function() {
z = this._z;
}
});
test('Firefox using Firefox', function() {
z.appMatchesUserAgent = true;
z.app = 'firefox';
z.browser.firefox = true;
z.browserVersion = '10.0';
z.platform = 'mac';
autofillPlatform(this.sandbox);
equal($('input[name=appver]', this.sandbox).val(), z.browserVersion);
equal($('input[name=platform]', this.sandbox).val(), z.platform);
});
test('Thunderbird using Firefox', function() {
z.appMatchesUserAgent = false;
z.app = 'thunderbird';
z.browser.firefox = true;
z.browserVersion = '10.0';
z.platform = 'mac';
autofillPlatform(this.sandbox);
equal($('input[name=appver]', this.sandbox).val(), '');
equal($('input[name=platform]', this.sandbox).val(), '');
});
test('Thunderbird using Thunderbird', function() {
z.appMatchesUserAgent = true;
z.app = 'thunderbird';
z.browser.thunderbird = true;
z.browserVersion = '10.0';
z.platform = 'mac';
autofillPlatform(this.sandbox);
equal($('input[name=appver]', this.sandbox).val(), z.browserVersion);
equal($('input[name=platform]', this.sandbox).val(), z.platform);
});
module('Pjax Search', {
setup: function() {
this.container = $('#pjax-results', this.sandbox);
this.filters = $('#search-facets', this.sandbox);
this.container.initSearchPjax(this.filters);
}
});
test('Loading', function() {
var loaded = false;
this.container.bind('search.loading', function() {
loaded = true;
});
$.when(this.container.trigger('start.pjax')).done(function() {
ok(loaded);
})
});
test('Finished', function() {
var finished = false;
this.container.bind('search.finished', function() {
finished = true;
});
$.when(this.container.trigger('end.pjax')).done(function() {
ok(finished);
})
});
test('Rebuild links', function() {
function check(s, expected) {
// rebuildLink accepts the following parameters:
// 1) previous target URL,
// 2) fixed URL params,
// 3) new query string (i.e, location.search)
equal(rebuildLink(s[0], s[1], s[2]), expected);
}
// We're showing results for Macs, so the filter URLs should get updated
// to reflect that.
check(['/en-US/firefox/search/?q=adblock&amp;appver=10.0',
'{"appver": "10.0"}',
'?q=adblock&platform=mac'],
'/en-US/firefox/search/?q=adblock&platform=mac&appver=10.0');
// We're showing results filtered by cat 14, so the filter URL for cat 72
// should not change values.
check(['/en-US/firefox/search/?q=adblock&amp;appver=8.0&amp;cat=72&amp;atype=1',
'{"atype": 1, "cat": 72}',
'?q=adblock&cat=14&atype=1'],
'/en-US/firefox/search/?q=adblock&cat=72&atype=1');
// We're showing results filtered by cat 14, so the filter URL to show
// all categories/types should not contain cat=14.
check(['/en-US/firefox/search/?q=adblock',
'{"atype": null, "cat": null}',
'?q=adblock&cat=14'],
'/en-US/firefox/search/?q=adblock&cat=&atype=');
});

Просмотреть файл

@ -1,41 +0,0 @@
module('Serializers');
test('getVars', function() {
function check(s, excl, expected) {
tests.equalObjects(z.getVars(s, excl), expected);
}
check('', false, {});
check('?', false, {});
check('?a', true, {});
check('?a', false, {'a': undefined});
check('?==a', true, {});
check('?==a', false, {});
check('?a=apple&a=apricot', false, {'a': 'apricot'});
check('?a=apple&b=banana&c=carrot', false,
{'a': 'apple', 'b': 'banana', 'c': 'carrot'});
check('?a?a=apple', false, {'a?a': 'apple'});
check('?a=apple&b?c=banana', false, {'a': 'apple', 'b?c': 'banana'});
check('?a=b=c&d=e', false, {'a': 'b', 'd': 'e'});
check('?<script>alert("xss")</script>="a"', false,
{'&lt;script&gt;alert(&#34;xss&#34;)&lt;/script&gt;': '&#34;a&#34;'});
check('?"a"=<script>alert("xss")</script>', false,
{'&#34;a&#34;': '&lt;script&gt;alert(&#34;xss&#34;)&lt;/script&gt;'});
});
test('JSON.parseNonNull', function() {
function check(s, expected) {
tests.equalObjects(JSON.parseNonNull(s), JSON.parse(expected));
}
check('[]', '[]');
check('{}', '{}');
check('{"x": "xxx", "y": "yyy"}',
'{"x": "xxx", "y": "yyy"}');
check('{"x": "null", "y": null}',
'{"x": "null", "y": ""}');
check('[{"x": "null", "y": null}, {"x": "null", "y": null}]',
'[{"x": "null", "y": ""}, {"x": "null", "y": ""}]');
check('[{"w": {"x": null, "y": {"z": null}}}]',
'[{"w": {"x": "", "y": {"z": ""}}}]');
});

Просмотреть файл

@ -1,35 +0,0 @@
$(document).ready(function() {
var storageFixture = {
setup: function() {
this.s = z.Storage();
this.s_fruit = z.Storage('fruit');
this.s_candy = z.Storage('candy');
}
};
module('storage', storageFixture);
test('Non-namespaced storage', function() {
this.s.set('a', 'aaa');
equals(localStorage.getItem('a'), 'aaa');
equals(this.s.get('a'), 'aaa');
this.s.remove('a');
equals(this.s.get('a'), null);
equals(localStorage.getItem('a'), null);
});
test('Namespaced storage', function() {
this.s_fruit.set('a', 'apple');
this.s_candy.set('a', 'airheads');
equals(this.s_fruit.get('a'), 'apple');
equals(localStorage.getItem('fruit-a'), 'apple');
this.s_fruit.remove('a');
equals(this.s_fruit.get('a'), null);
equals(localStorage.getItem('fruit-a'), null);
equals(this.s_candy.get('a'), 'airheads');
});
});

Просмотреть файл

@ -1,368 +0,0 @@
module('Search Suggestions', {
setup: function() {
this.sandbox = tests.createSandbox('#search-suggestions');
this.results = $('#site-search-suggestions', this.sandbox);
this.input = $('#search #search-q', this.sandbox);
this.input.searchSuggestions(this.results, processResults, true);
this.url = this.results.attr('data-src');
this.newItems = {'ajax': [], 'cache': []};
z._AjaxCache = {};
$.mockjaxClear();
$.mockjaxSettings = {
status: 200,
responseTime: 0,
contentType: 'text/json',
dataType: 'json'
};
},
teardown: function() {
this.sandbox.remove();
$.mockjaxClear();
},
mockRequest: function() {
this.jsonResults = [];
for (var i = 0; i < 10; i++) {
this.jsonResults.push({'id': i, 'url': 'dekKobergerStudios.biz'});
}
$.mockjax({
url: this.url,
responseText: JSON.stringify(this.jsonResults),
status: 200,
responseTime: 0
});
},
testInputEvent: function(eventType, fail) {
var self = this,
$input = self.input,
$results = self.results,
query = '<script>alert("xss")</script>';
self.mockRequest();
if (fail) {
var inputIgnored = false;
// If we send press a bad key, this will check that we ignored it.
self.sandbox.bind('inputIgnored', function(e) {
inputIgnored = true;
});
tests.waitFor(function() {
return inputIgnored;
}).thenDo(function() {
ok(inputIgnored);
start();
});
} else {
self.sandbox.bind('resultsUpdated', function(e, items) {
tests.equalObjects(items, self.jsonResults);
var expected = escape_(query).replace(/&#39;/g, "'")
.replace(/&#34;/g, '"');
equal($results.find('.wrap p a.sel b').html(),
'"' + expected + '"');
start();
});
}
$input.val(query);
$input.triggerHandler(eventType);
},
testRowSelector: function(eventWhich, rowIndex) {
var $input = this.input,
$results = this.results,
expected = null;
this.sandbox.bind('selectedRowUpdate', function(e, row) {
expected = row;
});
tests.waitFor(function() {
return expected !== null;
}).thenDo(function() {
// Row index is zero-based. There are four rows: one for the
// placeholder and three results.
equal(expected, rowIndex,
'Expected row ' + rowIndex + ' to be highlighted');
start();
});
// Let's pretend we made a query. Generate three result rows.
for (var i = 0; i < 3; i++) {
$results.append('<li><a></li>');
}
// Initialize highlighting.
$results.trigger('highlight', ['xxx']);
// Simulate keystrokes.
$input.val('xxx');
$input.triggerHandler({type: 'keydown', which: eventWhich});
},
testKeyIgnored: function(event) {
var $input = this.input,
$results = this.results,
expected = null;
this.sandbox.bind('keyIgnored', function(e) {
expected = true;
});
tests.waitFor(function() {
return expected !== null;
}).thenDo(function() {
ok(expected, 'Key binding should have been ignored');
start();
});
// Initialize highlighting.
$results.trigger('highlight', ['xxx']);
// Simulate keystrokes.
$input.val('xxx').triggerHandler(event);
}
});
function processResults(settings) {
if (!settings || !settings.category) {
return;
}
// Update the 'Search add-ons for <b>"{addon}"</b>' text.
settings['$results'].find('p b').html(format('"{0}"',
settings.searchTerm));
var li_item = template(
'<li><a href="{url}"><span {cls} {icon}>{name}</span>{subtitle}</a></li>'
);
$.ajaxCache({
url: settings['$results'].attr('data-src'),
data: settings['$form'].serialize() + '&cat=' + settings.category,
newItems: function(formdata, items) {
var eventName;
if (items !== undefined) {
var ul = '';
$.each(items, function(i, item) {
var d = {
url: escape_(item.url) || '#',
icon: '',
cls: '',
subtitle: '',
};
if (item.icons['32']) {
d.icon = format(
'style="background-image:url({0})"',
escape_(item.icons['32'])
);
}
if (item.cls) {
d.cls = format('class="{0}"',
escape_(item.cls));
if (item.cls == 'cat') {
d.subtitle = format(
' <em class="subtitle">{0}</em>',
gettext('Category')
);
}
}
if (item.name) {
d.name = escape_(item.name);
// Append the item only if it has a name.
ul += li_item(d);
}
});
settings['$results'].find('ul').html(ul);
}
settings['$results'].trigger('highlight', [settings.searchTerm])
.trigger('resultsUpdated', [items]);
}
});
}
test('Generated HTML tags', function() {
var $results = this.results,
$sel = $results.find('.wrap p a.sel');
equal($sel.length, 1);
equal($sel.find('b').length, 1);
equal($results.find('.wrap ul').length, 1);
});
test('Default search label', function() {
var $results = this.results,
$input = this.input;
function check(cat, expected) {
$results.attr('data-cat', cat);
$.when($input.searchSuggestions($results, processResults, true))
.done(function() {
equal($results.find('p a.sel').text(), expected);
});
}
check('', 'Search add-ons for {0}');
check('all', 'Search add-ons for {0}');
check('themes', 'Search themes for {0}');
check('apps', 'Search apps for {0}');
});
test('Highlight search terms', function() {
var items = [
// Input, highlighted output
['', ''],
['x xx', 'x xx'],
['xxx', '<b>xxx</b>'],
[' XxX', ' <b>XxX</b>'],
['XXX', '<b>XXX</b>'],
['An XXX-rated add-on', 'An <b>XXX</b>-rated add-on'],
['Myxxx', 'My<b>xxx</b>'],
['XXX xxx XXX', '<b>XXX</b> <b>xxx</b> <b>XXX</b>'],
// Ignore non-alphanumeric characters (i.e., regex chars).
['xxx: xxx', '<b>xxx</b>: <b>xxx</b>'],
['xxx (){}[]*+:=?!\|^$. xxx', '<b>xxx</b> (){}[]*+:=?!\|^$. <b>xxx</b>']
];
var $ul = $('<ul>');
_.each(items, function(element) {
$ul.append($('<li>', {'html': element[0]}));
});
$.when($ul.find('li').highlightTerm('xxx')).done(function() {
$ul.find('li').each(function(index) {
equal($(this).html(), items[index][1]);
});
});
});
asyncTest('Results upon good keyup', function() {
this.testInputEvent({type: 'keyup', which: 'x'.charCodeAt(0)});
});
asyncTest('Results upon bad keyup', function() {
this.testInputEvent({type: 'keyup', which: 16}, true);
});
asyncTest('Results upon paste', function() {
this.testInputEvent('paste');
});
asyncTest('Hide results upon escape/blur', function() {
var $input = this.input,
$results = this.results;
$input.val('xxx').triggerHandler('blur');
tests.lacksClass($results, 'visible');
start();
});
asyncTest('Key bindings: Hijacked: arrow up', function() {
this.testRowSelector(z.keys.UP, 0);
});
asyncTest('Key bindings: Hijacked: arrow down', function() {
this.testRowSelector(z.keys.DOWN, 1);
});
asyncTest('Key bindings: Ignored: home', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.HOME});
});
asyncTest('Key bindings: Ignored: end', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.END});
});
asyncTest('Key bindings: Ignored: page up', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.PAGE_UP});
});
asyncTest('Key bindings: Ignored: page down', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.PAGE_DOWN});
});
asyncTest('Key bindings: Ignored: alt + home', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.HOME, altKey: true});
});
asyncTest('Key bindings: Ignored: ctrl + home', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.HOME, ctrlKey: true});
});
asyncTest('Key bindings: Ignored: meta + home', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.HOME, metaKey: true});
});
asyncTest('Key bindings: Ignored: shift + home', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.HOME, shiftKey: true});
});
asyncTest('Key bindings: Ignored: alt + end', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.END, altKey: true});
});
asyncTest('Key bindings: Ignored: ctrl + end', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.END, ctrlKey: true});
});
asyncTest('Key bindings: Ignored: meta + end', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.END, metaKey: true});
});
asyncTest('Key bindings: Ignored: shift + end', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.END, shiftKey: true});
});
asyncTest('Key bindings: Ignored: alt + left', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.LEFT, altKey: true});
});
asyncTest('Key bindings: Ignored: alt + right', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.RIGHT, altKey: true});
});
asyncTest('Key bindings: Ignored: ctrl + left', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.LEFT, ctrlKey: true});
});
asyncTest('Key bindings: Ignored: ctrl + right', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.RIGHT, ctrlKey: true});
});
asyncTest('Key bindings: Ignored: meta + left', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.LEFT, metaKey: true});
});
asyncTest('Key bindings: Ignored: meta + right', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.RIGHT, metaKey: true});
});
asyncTest('Key bindings: Ignored: shift + left', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.LEFT, shiftKey: true});
});
asyncTest('Key bindings: Ignored: shift + right', function() {
this.testKeyIgnored({type: 'keydown', which: z.keys.RIGHT, shiftKey: true});
});
asyncTest('Cached results do not change', function() {
var self = this,
$input = self.input,
$results = self.results,
query = 'xxx';
self.mockRequest();
self.sandbox.bind('resultsUpdated', function(e, items) {
equal($results.find('.wrap p a.sel b').text(), '"' + query + '"');
tests.equalObjects(items, self.jsonResults);
if (z._AjaxCache === undefined) {
$input.triggerHandler('paste');
} else {
tests.waitFor(function() {
return z._AjaxCache;
}).thenDo(function() {
var cache = z.AjaxCache(self.url + ':get'),
fields = self.sandbox.find('form').serialize(),
args = JSON.stringify(fields + '&cat=' + $results.attr('data-cat'));
tests.equalObjects(cache.items[args], items);
tests.equalObjects(cache.previous.data, items);
equal(cache.previous.args, args);
start();
});
}
});
$input.val(query);
$input.triggerHandler('paste');
});

Просмотреть файл

@ -1,14 +0,0 @@
{
"name": "Main Test Suite",
"extra_media_urls": [
"js/lib/jstestnet.js",
"js/lib/stacktrace.js",
"js/zamboni/tests.js",
"js/zamboni/debouncer.js",
"js/zamboni/devhub.js",
"js/zamboni/validator.js",
"js/zamboni/editors.js",
"js/zamboni/files.js",
"js/zamboni/password-strength.js"
]
}

Просмотреть файл

@ -1,46 +0,0 @@
module('Truncation', {
setup: function() {
this.sandbox = tests.createSandbox();
}
});
test('lineclamp: none', function() {
var $src = $('<p>ballin</p>').appendTo(this.sandbox);
// Check that we return the same thing.
equal($src.lineclamp(), $src);
// Check that `max-height` was not set.
equal($src.css('max-height'), 'none');
});
test('lineclamp: round', function() {
var $src = $('<p>ballin</p>').appendTo(this.sandbox);
// Set some arbitrary `line-height`.
$src.css('line-height', '14.2px');
// Check that we return the same thing.
equal($src.lineclamp(1), $src);
// If we're clamping one line with a `line-height` of 14.2px, then the
// `max-height` should be 15px.
equal($src.css('max-height'), '15px');
});
test('lineclamp: normal', function() {
var $src = $('<p>ballin</p>').appendTo(this.sandbox);
// Set some arbitrary `line-height`.
$src.css('line-height', '15px');
// Check that we return the same thing.
equal($src.lineclamp(2), $src);
// If we're clamping two lines whose `line-height` are 15px, then the
// `max-height` should be 50px.
equal($src.css('max-height'), '30px');
});

Просмотреть файл

@ -1,25 +0,0 @@
$(document).ready(function(){
module('format');
test('String Formatting', function() {
equals(format("{0}{1}", ['a', 'b']), "ab");
equals(format("{0}{1}", 'a', 'b'), "ab");
equals(format("{x}{y}", {x: 'a', y: 'b'}), "ab");
});
module('escape_');
test('Entity Escaping', function() {
function check(s, expected) {
equal(escape_(s), expected);
}
check(undefined, undefined);
check('', '');
check("&&<<>>''\"\"", "&amp;&amp;&lt;&lt;&gt;&gt;&#39;&#39;&#34;&#34;");
check("<script>alert('\"xss\"')</script>&&",
"&lt;script&gt;alert(&#39;&#34;xss&#34;&#39;)&lt;/script&gt;&amp;&amp;");
});
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -112,7 +112,6 @@ suds==0.4
-e git+https://github.com/washort/django-cache-machine@4690198122a96a88267323566dc18a5e0437681f#egg=django-cache-machine
## Forked.
-e git+https://github.com/andymckay/django-piston-oauth2.git@177aaf937860318af8d9c2bb74adc27860803eb9#egg=django-piston-oauth2
-e git+https://github.com/kumar303/django-qunit.git@b0f468dcf33439488158c845df37ef3261852b55#egg=django-qunit
-e git+https://github.com/andymckay/django-uuidfield.git@029dd1263794ec36c327617cd6c2346da81c8c33#egg=django-uuidfield
-e git+https://github.com/washort/django-mysql-pool.git@47b7bc35a7b00a9798d4fe4792764ab00bfcb5b6#egg=django-mysql-pool

Просмотреть файл

@ -3,5 +3,4 @@
-r prod.txt
psutil==0.2.0
jstestnetlib==0.3
nose-blockage==0.1.2

Просмотреть файл

@ -1,31 +0,0 @@
"""
A wrapper around nosetests to run JavaScript tests in a CI environment.
Example::
python run_jstests.py --with-xunit \
--with-django-serv --django-host hudson.mozilla.org \
--with-jstests \
--jstests-server http://jstestnet.farmdev.com/ \
--jstests-suite zamboni --jstests-browsers firefox
"""
import os
import site
import subprocess
ROOT = os.path.join(os.path.dirname(__file__), '..')
site.addsitedir(os.path.join(ROOT, 'vendor'))
site.addsitedir(os.path.join(ROOT, 'vendor/lib/python'))
from jstestnetlib.noseplugins import JSTests, DjangoServPlugin
import nose
def main():
nose.main(addplugins=[DjangoServPlugin(ROOT), JSTests()])
if __name__ == '__main__':
main()

Просмотреть файл

@ -1,102 +0,0 @@
# This script should be called from within Hudson
cd $WORKSPACE
VENV=$WORKSPACE/venv
VENDOR=$WORKSPACE/vendor
LOCALE=$WORKSPACE/locale
LOG=$WORKSPACE/jstests-runserver.log
echo "Starting build on executor $EXECUTOR_NUMBER..." `date`
if [ -z $1 ]; then
echo "Warning: You should provide a unique name for this job to prevent database collisions."
echo "Usage: $0 <name>"
echo "Continuing, but don't say you weren't warned."
fi
echo "Setup..." `date`
# Make sure there's no old pyc files around.
find . -name '*.pyc' | xargs rm
if [ ! -d "$VENV/bin" ]; then
echo "No virtualenv found. Making one..."
virtualenv $VENV --system-site-packages
fi
source $VENV/bin/activate
pip install -U --exists-action=w --no-deps -q -r requirements/compiled.txt -r requirements/test.txt
# Create paths we want for addons
if [ ! -d "/tmp/warez" ]; then
mkdir /tmp/warez
fi
if [ ! -d "$LOCALE" ]; then
echo "No locale dir? Cloning..."
svn co http://svn.mozilla.org/addons/trunk/site/app/locale/ $LOCALE
fi
if [ ! -d "$VENDOR" ]; then
echo "No vendor lib? Cloning..."
git clone --recursive git://github.com/mozilla/zamboni-lib.git $VENDOR
fi
# Update the vendor lib.
echo "Updating vendor..."
git submodule --quiet foreach 'git submodule --quiet sync'
git submodule --quiet sync && git submodule update --init --recursive
cp -f docs/settings/settings_local.dev.py settings_local.py
cat >> settings_local.py <<SETTINGS
ROOT_URLCONF = 'lib.urls_base'
LOG_LEVEL = logging.ERROR
DATABASES = {
'default': {
'NAME': 'zamboni_$1',
'HOST': 'localhost',
'ENGINE': 'django.db.backends.mysql',
'USER': 'hudson',
'OPTIONS': {'init_command': 'SET storage_engine=InnoDB'},
'TEST_NAME': 'test_zamboni_$1',
'TEST_CHARSET': 'utf8',
'TEST_COLLATION': 'utf8_general_ci',
},
}
CACHES = {
'default': {
'BACKEND': 'caching.backends.locmem.LocMemCache',
}
}
CELERY_ALWAYS_EAGER = True
ADDONS_PATH = '/tmp/warez'
# Activate Qunit:
INSTALLED_APPS += (
'django_qunit',
)
JINGO_EXCLUDE_APPS += (
'qunit',
)
SETTINGS
# All DB tables need to exist so that runserver can start up.
python manage.py syncdb --noinput
echo "Starting JS tests..." `date`
rm $LOG
cd scripts
# Some of these env vars are set in the Jenkins build step.
BROWSERS=firefox
XARGS="-v --with-xunit --with-django-serv --django-host $DJANGO_HOST --django-port $DJANGO_PORT --django-log $LOG --django-startup-uri /robots.txt --django-root-dir $WORKSPACE --with-jstests --jstests-server http://jstestnet.farmdev.com/ --jstests-suite zamboni --jstests-token $JSTESTS_TOKEN --jstests-browsers $BROWSERS --debug nose.plugins.jstests"
python run_jstests.py --jstests-url http://$DJANGO_HOST:$DJANGO_PORT/en-US/qunit/ --xunit-file=nosetests.xml $XARGS
echo 'shazam!'

Просмотреть файл

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>QUnit Test Suite</title>
<link rel="stylesheet" href="{{ url('qunit_css') }}?v={{ timestamp }}" type="text/css" media="screen">
</head>
<body
data-app="{{ request.APP.short }}"
data-appname="{{ request.APP.pretty }}"
data-appid="{{ request.APP.id }}"
data-min-beta-version="{{ settings.MIN_BETA_VERSION }}"
data-nightly-version="8.0"
data-anonymous="true"
data-readonly="false"
data-media-url="{{ MEDIA_URL }}"
data-paypal-url="/paypal"
data-default-locale="en-us">
<h1 id="qunit-header">QUnit Test Suite ({{ suite.name }})</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
{% if in_directory or subsuites %}
<div id="navigation">
{% if in_subdirectory %}
<a href="{{ url('qunit_test_overview', previous_directory) }}">..</a>
{% endif %}
{% for suite in subsuites %}
<a href="{{ suite }}/">{{ suite }}</a>
{% endfor %}
</div>
{% endif %}
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>
<div id="sandbox"><!-- custom Zamboni sandbox area --></div>
{% block fixtures %}
{% endblock %}
<script type="text/javascript">
waffle = {
flag: function () { return true; },
switch: function () { return true; },
sample: function () { return true; }
}
</script>
<script src="{{ static(url('jsi18n')) }}"></script>
{% block init_scripts %}
{% endblock %}
<script async defer src="{{ static(url('addons.buttons.js')) }}"></script>
<script type="text/javascript" src="{{ url('qunit_js') }}?v={{ timestamp }}"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/lib/jquery.mockjax.js?v={{ timestamp }}"></script>
{% for url in suite.extra_urls %}
<script type="text/javascript" src="{{ url }}?v={{ timestamp }}"></script>
{% endfor %}
{% for url in suite.extra_media_urls %}
<script type="text/javascript" src="{{ MEDIA_URL }}{{ url }}?v={{ timestamp }}"></script>
{% endfor %}
{% for file in files %}
<script type="text/javascript" src="{{ url('qunit_test', file) }}?v={{ timestamp }}"></script>
{% endfor %}
</body>
</html>

Просмотреть файл

@ -1,845 +0,0 @@
{% extends "qunit/base.html" %}
{% block init_scripts %}
{{ js('preload') }}
{{ js('impala') }}
{{ js('zamboni/devhub') }}
{% endblock %}
{% block fixtures %}
{# The following HTML can be applied to #qunit-fixture in test setup #}
<div id="exists">
<span class="exists"></span>
</div>
<div id="csrf-template">
<input id="csrfmiddlewaretoken" name="csrfmiddlewaretoken"
value="<csrf-from-input>">
</div>
<div id="l10n-translation">
<div data-name="summary" class="trans" id="trans-summary">
<textarea lang="en-us" name="summary_en-us" cols="40" rows="10"
id="id_summary_0" style="display: block;">
Firebug integrates with Firefox to put a wealth of development tools...
</textarea>
<textarea lang="ja" name="summary_ja" cols="40" rows="10" id="id_summary_1"
style="display: none;">
Firebug は、Web ページを閲覧中にクリック一つで使える豊富な開発ツールを Firefox に統合します。あなたはあらゆる
</textarea>
</div>
</div>
<div id="l10n-menu">
<ul>
<li><a href="#en-us" class="default-locale">English (US)</a></li>
<li><a href="#ja">日本語</a></li>
<li><a href="#id">Bahasa Indonesia</a></li>
</ul>
</div>
<div id="buttons">
<h2 class="addon"><span class="version"></span></h2>
<div id="addon-summary">
<table>
<tr class="addon-compatible"><td></td></tr>
<tr class="addon-updated"><td></td></tr>
</table>
</div>
<div class="install-shell">
<div class="install featuredaddon" data-version-supported="false"></div>
</div>
<div class="backup-button hidden">
<div class="install-shell">
<div class="install featuredaddon"
data-min=""
data-max=""
data-version="0.2"
data-compatible-apps="Fx 1.0"
data-lastupdated-isotime="today"
data-lastupdated-datetime="today"
data-version-supported="true">
</div>
</div>
</div>
</div>
<div id="button-d2c-compatible">
<div class="install-shell">
<div class="install"
data-min="4.0"
data-max="5.0"
data-is-compatible="true"
data-is-compatible-app="true"
data-compat-overrides="[]">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
</div>
</div>
<div id="button-d2c-compatible-override">
<div class="install-shell">
<div class="install"
data-min="4.0"
data-max="5.0"
data-is-compatible="true"
data-is-compatible-app="true"
data-compat-overrides="{{ [['10.0a1', '99.*']]|json }}">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
<div class="d2c-reasons-popup popup"><ul></ul></div>
</div>
</div>
<div id="button-d2c-not-compatible">
<div class="install-shell">
<div class="install"
data-min="4.0"
data-max="5.0"
data-is-compatible="false"
data-is-compatible-app="false"
data-compat-overrides="[]">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
</div>
</div>
<div id="button-d2c-older-browser">
<div class="install-shell">
<div class="install"
data-min="98.0"
data-max="99.0"
data-is-compatible="true"
data-is-compatible-app="true"
data-compat-overrides="[]">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
</div>
</div>
<div id="button-d2c-old-max">
<div class="install-shell">
<div class="install"
data-min="3.0"
data-max="3.5"
data-is-compatible="true"
data-is-compatible-app="true"
data-compat-overrides="[]">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
</div>
</div>
<div id="files-wrapper">
<div id="files">
<ul>
<li><a class="file" href="">someurl</a></li>
<li><a class="directory closed" href="">foo</a></li>
<ul class="js-hidden">
<li><a class="file" href="someurl">foo/bar.txt</a></li>
</ul>
</ul>
<input type="checkbox" id="toggle-known">
</div>
</div>
<div id="paypal">
<div class="contribute">
<a href="/paykey?src=direct" class="suggested-amount">Contribute</a>
</div>
</div>
<div id="password-strength">
<input type="password" data-min-length="8" />
</div>
<div id="personas">
<fieldset>
<legend>Persona License</legend>
<input type="hidden" name="license" id="id_license">
<div id="cc-chooser">
<h3>Can others share your Persona, as long as you're given credit?</h3>
<ul>
<li><label><input type="radio" name="cc-attrib" value="0"> Yes</label></li>
<li><label><input type="radio" name="cc-attrib" value="1"> No</label></li>
</ul>
<h3>Can others make commercial use of your Persona?</h3>
<ul>
<li><label><input type="radio" name="cc-noncom" value="0"> Yes</label></li>
<li><label><input type="radio" name="cc-noncom" value="1"> No</label></li>
</ul>
<h3>Can others create derivative works from your Persona?</h3>
<ul>
<li><label><input type="radio" name="cc-noderiv" value="0"> Yes</label></li>
<li><label><input type="radio" name="cc-noderiv" value="1"> Yes, as long as they share alike</label></li>
<li><label><input type="radio" name="cc-noderiv" value="2"> No</label></li>
</ul>
<div id="persona-license">
<p>Your Persona will be released under the following license:</p>
<p id="cc-license" class="license icon"></p>
<p class="select-license">
<a href="#">Select a different license.</a>
</p>
</div>
</div>
<div id="persona-license-list" class="hidden">
<h3>Select a license for your Persona.</h3>
<ul>
<li><label><input type="radio" name="license" value="7"> All Rights Reserved</label></li>
<li><label><input type="radio" name="license" value="9"> Creative Commons Attribution 3.0</label></li>
<li><label><input type="radio" name="license" value="10"> Creative Commons Attribution-NonCommercial 3.0</label></li>
<li><label><input type="radio" name="license" value="11"> Creative Commons Attribution-NonCommercial-NoDerivs 3.0</label></li>
<li><label><input type="radio" name="license" value="8"> Creative Commons Attribution-Noncommercial-Share Alike 3.0</label></li>
<li><label><input type="radio" name="license" value="12"> Creative Commons Attribution-NoDerivs 3.0</label></li>
<li><label><input type="radio" name="license" value="13"> Creative Commons Attribution-ShareAlike 3.0</label></li>
</ul>
</div>
</fieldset>
</div>
<div id="browserid-test">
<section class="primary"></section>
<a class="browserid-login" href="#" data-url="/nowhere">BrowserID Login</a>
</div>
<div id="upsell-test">
<form action="/en-US/developers/addon/status-watch/payments" method="post">
<div class="brform">
<div>
<ul>
<li><label for="id_do_upsell_0"><input type="radio" name="do_upsell" value="0" id="id_do_upsell_0" checked="checked"> I don't have a free add-on to associate.</label></li>
<li><label for="id_do_upsell_1"><input type="radio" name="do_upsell" value="1" id="id_do_upsell_1"> This is a premium upgrade to:</label></li>
</ul>
</div>
<div class="indent">
<div>
<select id="id_free" name="free">
<option selected="selected" value=""></option>
</select>
</div>
<div><textarea name="text" cols="40" rows="10" id="id_text"></textarea></div>
</div>
</div>
<button type="submit">Save Changes</button>
</form>
</div>
<div id="search-suggestions">
<form id="search" action="/en-us/firefox/search/">
<input id="search-q" type="text" name="q" required autocomplete="off" title=""
class="text placeholder" placeholder="search for add-ons" value="">
<div id="site-search-suggestions" data-src="/askjeeves" data-cat="all"></div>
</form>
</div>
<div id="search-box">
<form id="search" action="/en-us/firefox/search/">
<input type="text" id="search-q" name="q">
<input type="hidden" name="appver" id="id_appver">
<input type="hidden" name="platform" id="id_platform">
</form>
</div>
<div id="pjax-search">
<div id="search-facets">
<ul class="facets island pjax-trigger"></ul>
</div>
<div id="pjax-results"></div>
</div>
<div id="balloons">
<div class="site-tip" id="appruntime-pitch" style="display: none">
<p>Check out the App Runtime extension. It's baller.</p>
<a href="#" class="close">Close</a>
</div>
</div>
<div id="amo-promos">
<section id="promos" class="island" style="display: none">
<div>
<ul class="slider">
<li class="panel"><section id="starter"></section></li>
<li class="panel"><section id="ryff"></section></li>
</ul>
</div>
</section>
</div>
<div id="apps-error-msg">
{% include 'addons/includes/apps_error_msg.html' %}
</div>
<!-- Install button tests - it's possible not all combinations are being tested here -->
<div id="install-button">
<div class="install-shell">
<div class="install" data-min="3.0" data-max="4.0">
<p class="install-button">
<a class="button download" data-hash="1337" href="http://testurl.com">Foo</a>
</p>
</div>
</div>
</div>
<!-- app, warning, mobile -->
<div id="install-button-warning">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': True,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- app, eula, mobile -->
<div id="install-button-eula">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- premium, mobile -->
<div id="install-button-premium">
{% with addon={'is_premium': Mock(return_value=True),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- contrib, mobile -->
<div id="install-button-contrib">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': True,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- can be purchased, mobile -->
<div id="install-button-purchasable">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- marketplace, mobile, can be purchased -->
<div id="install-button-marketplace">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- app, marketplace, mobile, can be purchased -->
<div id="install-button-app-marketplace">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- app, premium, mobile -->
<div id="install-button-app-premium">
{% with addon={'is_premium': Mock(return_value=True),
'is_webapp': Mock(return_value=True),
'has_purchased': Mock(return_value=False),
'premium': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- app, contrib, mobile -->
<div id="install-button-app-contrib">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': True,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- app, can be purchased, mobile -->
<div id="install-button-app-purchasable">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=False)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- marketplace, app, warning, mobile -->
<div id="install-button-mp-warning">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': True,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- marketplace, app, eula, mobile -->
<div id="install-button-mp-eula">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=True)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- marketplace, premium, mobile -->
<div id="install-button-mp-premium">
{% with addon={'is_premium': Mock(return_value=True),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': False,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<!-- marketplace, contrib, mobile -->
<div id="install-button-mp-contrib">
{% with addon={'is_premium': Mock(return_value=False),
'is_webapp': Mock(return_value=False)},
b={'show_warning': False,
'addon': {'get_url_path': Mock(return_value='http://testurl.com')},
'show_contrib': True,
'xpiurl': 'http://xpiurl.com',
'button_class': ['download', 'prominent']},
link={'url': 'http://testurl.com',
'os': {'name': 'windows'},
'file': {'hash': '1337'}},
shared_url=Mock(return_value='http://sharedurl.com'),
waffle={'switch': Mock(return_value=True)},
request={'MOBILE': True} %}
{% include 'addons/includes/install_button.html' %}
{% endwith %}
</div>
<div id="addon-validator-template">
<div class="addon-validator-suite" id="addon-validator-suite-test"
data-validateurl="/validate">
{% with validate_url="/validate" %}
{% include "devhub/addons/includes/validation_test_results.html" %}
{% endwith %}
</div>
</div>
<div id="addon-compatibility-template">
<div class="addon-validator-suite" id="addon-validator-suite-test"
data-validateurl="/validate">
{% with app_trans={'{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'Firefox'},
version_change_links={'{ec8030f7-c20a-464f-9b0e-13a3a9e97384} 6.*': '/firefox-6-changes'},
target_version={'{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': '6.*'} %}
{% include "devhub/addons/includes/validation_compat_test_results.html" %}
{% endwith %}
</div>
</div>
<div id="preview-list">
<div id="edit-addon-media">
<div id="file-list">
<div class="preview">
<span class="handle" style="display: none;">&nbsp;</span>
<div class="preview-thumb" data-url="" style="background-image: url();">
</div>
<input type="hidden" id="id_files-0-id" name="files-0-id">
<span class="js-hidden delete"><input type="checkbox" id="id_files-0-DELETE" name="files-0-DELETE"><label for="id_files-0-DELETE">Delete</label></span>
<div class="edit-previews-text">
<label class="above-the-field" data-for="files-0-caption" for="id_files-0-caption_0">
Please provide a caption for this screenshot:
<span class="locale">English (US)</span>
</label>
<div data-name="files-0-caption" class="trans" id="trans-files-0-caption"><textarea lang="en-us" id="id_files-0-caption_0" cols="40" name="files-0-caption_en-us" rows="10" class="unsaved"></textarea><textarea lang="init" class="trans-init" cols="40" name="files-0-caption_init" rows="10" style="display: none;"></textarea></div>
<a class="remove" href="#">x</a>
</div>
<div class="js-hidden position">
<input type="text" id="id_files-0-position" value="0" name="files-0-position">
</div>
<div class="preview_extra">
<input type="text" id="id_files-0-upload_hash" name="files-0-upload_hash">
</div>
</div>
</div>
</div>
</div>
<div id="addon-platform-chooser">
<!-- TODO(Kumar) create faux form objects and include add_file_modal.html here -->
<form method="post" id="create-addon" class="item">
<div class="platform">
<div class="desktop-platforms">
<label>Which desktop platforms is this file compatible with?</label>
<ul>
<li><label for="id_desktop_platforms_0">
<input value="1" checked="checked" name="desktop_platforms" id="id_desktop_platforms_0" type="checkbox" class="platform">
All Platforms</label></li>
<li><label for="id_desktop_platforms_1">
<input value="2" id="id_desktop_platforms_1" type="checkbox" class="platform" name="desktop_platforms">
Linux</label></li>
<li><label for="id_desktop_platforms_2">
<input value="3" type="checkbox" id="id_desktop_platforms_2" name="desktop_platforms" class="platform">
Mac OS X</label></li>
<li><label for="id_desktop_platforms_3">
<input value="5" class="platform" type="checkbox" id="id_desktop_platforms_3" name="desktop_platforms">
Windows</label> </li>
</ul>
</div>
<div class="mobile-platforms">
<label>Which mobile platforms is this file compatible with?</label>
<ul>
<li><label for="id_mobile_platforms_0">
<input value="9" type="checkbox" class="platform" name="mobile_platforms" id="id_mobile_platforms_0" />
All Platforms</label></li>
<li><label for="id_mobile_platforms_1">
<input value="7" id="id_mobile_platforms_1" type="checkbox" class="platform" name="mobile_platforms" />
Android</label></li>
<li><label for="id_mobile_platforms_2">
<input value="8" type="checkbox" id="id_mobile_platforms_2" name="mobile_platforms" class="platform" />
Maemo</label></li>
</ul>
</div>
</div>
</form>
</div>
<div id="addon-platform-exclusion">
<!-- TODO(Kumar) create faux form objects and include add_file_modal.html here -->
<div id="file-upload-template">
<form>
<!-- for testing this has to be a non-input element, since
you can't access ".file" on an input element -->
<div data-upload-url="/" id="upload-file-input"></div>
</form>
</div>
<div class="platform">
<div class="desktop-platforms">
<label>Which desktop platforms is this file compatible with?</label>
<ul>
<li><label for="id_desktop_platforms_0">
<input value="1" checked="checked" name="desktop_platforms" id="id_desktop_platforms_0" type="checkbox" class="platform">
All Platforms</label></li>
<li><label for="id_desktop_platforms_1">
<input value="2" id="id_desktop_platforms_1" type="checkbox" class="platform" name="desktop_platforms">
Linux</label></li>
<li><label for="id_desktop_platforms_2">
<input value="3" type="checkbox" id="id_desktop_platforms_2" name="desktop_platforms" class="platform">
Mac OS X</label></li>
<li><label for="id_desktop_platforms_3">
<input value="5" class="platform" type="checkbox" id="id_desktop_platforms_3" name="desktop_platforms">
Windows</label> </li>
</ul>
</div>
<div class="mobile-platforms">
<label>Which mobile platforms is this file compatible with?</label>
<ul>
<li><label for="id_mobile_platforms_0">
<input value="9" type="checkbox" class="platform" name="mobile_platforms" id="id_mobile_platforms_0" />
All Platforms</label></li>
<li><label for="id_mobile_platforms_1">
<input value="7" id="id_mobile_platforms_1" type="checkbox" class="platform" name="mobile_platforms" />
Android</label></li>
<li><label for="id_mobile_platforms_2">
<input value="8" type="checkbox" id="id_mobile_platforms_2" name="mobile_platforms" class="platform" />
Maemo</label></li>
</ul>
</div>
</div>
</div>
<div id="slugified-field">
<input id="id_name" />
<span id="slug_edit" class="edit_with_prefix edit_initially_hidden">
<input type="text" maxlength="30" name="slug" id="id_slug">
</span>
<span id="slug_readonly">
<span id="slug_value"></span>
<a id="edit_slug" href="#">{{ _('Edit') }}</a>
</span>
</div>
<div id="addon-cats" data-max-categories="2">
<div data-max-categories="2">
<div id="addon-cats-fx" class="addon-app-cats">
<label>Select <b>up to 2</b> Firefox categories for this add-on:</label>
<ul class="addon-categories">
<li><label for="id_form-0-categories_0"><input type="checkbox" name="form-0-categories" value="72" id="id_form-0-categories_0" /> Alerts &amp; Updates</label></li>
<li><label for="id_form-0-categories_1"><input checked="checked" type="checkbox" name="form-0-categories" value="14" id="id_form-0-categories_1" /> Appearance</label></li>
<li><label for="id_form-0-categories_2"><input checked="checked" type="checkbox" name="form-0-categories" value="22" id="id_form-0-categories_2" /> Bookmarks</label></li>
</ul>
<ul class="addon-misc-category">
<li><label for="id_form-0-categories_13"><input type="checkbox" name="form-0-categories" value="73" id="id_form-0-categories_13" /> My add-on doesn&#39;t fit into any of the categories</label></li>
</ul>
</div>
<div id="addon-cats-tb" class="addon-app-cats">
<label>Select <b>up to 2</b> Thunderbird categories for this add-on:</label>
<ul class="addon-categories">
<li><label for="id_form-1-categories_0"><input type="checkbox" name="form-1-categories" value="23" id="id_form-1-categories_0" /> Contacts</label></li>
<li><label for="id_form-1-categories_1"><input type="checkbox" name="form-1-categories" value="69" id="id_form-1-categories_1" /> Language Support</label></li>
</ul>
<ul class="addon-misc-category">
<li><label for="id_form-1-categories_4"><input type="checkbox" name="form-1-categories" value="50" id="id_form-1-categories_4" /> My add-on doesn&#39;t fit into any of the categories</label></li>
</ul>
</div>
</div>
</div>
<div id="file-perf-tests">
{% with version={'all_files': [{'can_be_perf_tested': Mock(return_value=True), 'id': 1}]}, addon={'slug': 'foo'} %}
{% include "devhub/addons/listing/perf_file_listing.html" %}
{% endwith %}
</div>
<div id="editors-search-form">
<form>
<label for="id_application_id">Application</label>
<select data-url="/application_versions.json" name="application_id" id="id_application_id">
<option value="" selected="selected"></option>
<option value="1">Firefox</option>
<option value="2">Mozilla</option>
</select>
<label for="id_max_version">Max. Version</label>
<select name="max_version" id="id_max_version">
<option value="" selected="selected">Select an application first</option>
</select>
</form>
</div>
<div id="editors-motd-template">
<style>
/* We hide the message by default, and show it only if we're s'posed to. */
.daily-message { display: none }
</style>
{% with motd='This is an announcement' %}
{% include "editors/includes/daily-message.html" %}
{% endwith %}
</div>
<div id="editors-motd-for-edit-template">
{% with motd='This is an announcement' %}
{% include "editors/includes/daily-message.html" %}
{% endwith %}
<div id="editor-motd"><!-- admin edit form and stuff --></div>
</div>
<div id="hovercard-grid">
<div class="island">
<ul class="listing-grid">
<section>
<li></li>
<li></li>
<li></li>
</section>
<section>
<li></li>
<li></li>
<li></li>
</section>
<section>
<li></li>
<li></li>
<li></li>
</section>
</ul>
</div>
</div>
{% endblock %}