DEP 0003 -- Added JavaScript unit tests.
Setup QUnit, added tests, and measured test coverage. Thanks to Nick Sanford for the initial tests.
This commit is contained in:
parent
3bbaf84d65
commit
2d0dead224
|
@ -10,3 +10,4 @@ node_modules/
|
||||||
tests/coverage_html/
|
tests/coverage_html/
|
||||||
tests/.coverage
|
tests/.coverage
|
||||||
build/
|
build/
|
||||||
|
tests/report/
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
var globalThreshold = 50; // Global code coverage threshold (as a percentage)
|
||||||
|
|
||||||
|
module.exports = function(grunt) {
|
||||||
|
grunt.initConfig({
|
||||||
|
// Configuration to be run (and then tested).
|
||||||
|
blanket_qunit: {
|
||||||
|
default_options: {
|
||||||
|
options: {
|
||||||
|
urls: ['js_tests/tests.html?coverage=true&gruntReport'],
|
||||||
|
globalThreshold: globalThreshold,
|
||||||
|
threshold: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.loadNpmTasks('grunt-blanket-qunit');
|
||||||
|
grunt.registerTask('test', ['blanket_qunit']);
|
||||||
|
grunt.registerTask('default', ['test']);
|
||||||
|
};
|
|
@ -58,7 +58,85 @@ independently. The Closure Compiler library requires `Java`_ 7 or higher.
|
||||||
Please don't forget to run ``compress.py`` and include the ``diff`` of the
|
Please don't forget to run ``compress.py`` and include the ``diff`` of the
|
||||||
minified scripts when submitting patches for Django's JavaScript.
|
minified scripts when submitting patches for Django's JavaScript.
|
||||||
|
|
||||||
|
JavaScript tests
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Django's JavaScript tests can be run in a browser or from the command line.
|
||||||
|
The tests are located in a top level ``js_tests`` directory.
|
||||||
|
|
||||||
|
Writing tests
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Django's JavaScript tests use `QUnit`_. Here is an example test module:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
module('magicTricks', {
|
||||||
|
beforeEach: function() {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
$('#qunit-fixture').append('<button class="button"></button>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeOnClick removes button on click', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
removeOnClick('.button');
|
||||||
|
assert.equal($('.button').length === 1);
|
||||||
|
$('.button').click();
|
||||||
|
assert.equal($('.button').length === 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('copyOnClick adds button on click', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
copyOnClick('.button');
|
||||||
|
assert.equal($('.button').length === 1);
|
||||||
|
$('.button').click();
|
||||||
|
assert.equal($('.button').length === 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Please consult the QUnit documentation for information on the types of
|
||||||
|
`assertions supported by QUnit <https://api.qunitjs.com/category/assert/>`_.
|
||||||
|
|
||||||
|
Running tests
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The JavaScript tests may be run from a web browser or from the command line.
|
||||||
|
|
||||||
|
Testing from a web browser
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To run the tests from a web browser, open up ``js_tests/tests.html`` in your
|
||||||
|
browser.
|
||||||
|
|
||||||
|
To measure code coverage when running the tests, you need to view that file
|
||||||
|
over HTTP. To view code coverage:
|
||||||
|
|
||||||
|
* Execute ``python -m http.server`` (or ``python -m SimpleHTTPServer`` on
|
||||||
|
Python 2) from the root directory (not from inside ``js_tests``).
|
||||||
|
* Open http://localhost:8000/js_tests/tests.html in your web browser.
|
||||||
|
|
||||||
|
Testing from the command line
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To run the tests from the command line, you need to have `Node.js`_ installed.
|
||||||
|
|
||||||
|
After installing `Node.js`, install the JavaScript test dependencies by running
|
||||||
|
the following from the root of your Django checkout:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ npm install
|
||||||
|
|
||||||
|
Then run the tests with:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ npm test
|
||||||
|
|
||||||
.. _Closure Compiler: https://developers.google.com/closure/compiler/
|
.. _Closure Compiler: https://developers.google.com/closure/compiler/
|
||||||
.. _EditorConfig: http://editorconfig.org/
|
.. _EditorConfig: http://editorconfig.org/
|
||||||
.. _Java: https://www.java.com
|
.. _Java: https://www.java.com
|
||||||
.. _jshint: http://jshint.com/
|
.. _jshint: http://jshint.com/
|
||||||
|
.. _node.js: https://nodejs.org/
|
||||||
|
.. _qunit: https://qunitjs.com/
|
||||||
|
|
|
@ -621,6 +621,7 @@ Querysets
|
||||||
querystring
|
querystring
|
||||||
queueing
|
queueing
|
||||||
Quickstart
|
Quickstart
|
||||||
|
QUnit
|
||||||
quo
|
quo
|
||||||
quoteless
|
quoteless
|
||||||
Radziej
|
Radziej
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
module('admin.DateTimeShortcuts');
|
||||||
|
|
||||||
|
test('init', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
|
||||||
|
var dateField = $('<input type="text" class="vDateField" value="2015-03-16"><br>');
|
||||||
|
$('#qunit-fixture').append(dateField);
|
||||||
|
|
||||||
|
DateTimeShortcuts.init();
|
||||||
|
|
||||||
|
var shortcuts = $('.datetimeshortcuts');
|
||||||
|
assert.equal(shortcuts.length, 1);
|
||||||
|
assert.equal(shortcuts.find('a:first').text(), 'Today');
|
||||||
|
assert.equal(shortcuts.find('a:last .date-icon').length, 1);
|
||||||
|
});
|
|
@ -0,0 +1,22 @@
|
||||||
|
module('admin.RelatedObjectLookups');
|
||||||
|
|
||||||
|
test('html_unescape', function(assert) {
|
||||||
|
function assert_unescape(then, expected, message) {
|
||||||
|
assert.equal(html_unescape(then), expected, message);
|
||||||
|
}
|
||||||
|
assert_unescape('<', '<', 'less thans are unescaped');
|
||||||
|
assert_unescape('>', '>', 'greater thans are unescaped');
|
||||||
|
assert_unescape('"', '"', 'double quotes are unescaped');
|
||||||
|
assert_unescape(''', "'", 'single quotes are unescaped');
|
||||||
|
assert_unescape('&', '&', 'ampersands are unescaped');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('id_to_windowname', function(assert) {
|
||||||
|
assert.equal(id_to_windowname('.test'), '__dot__test');
|
||||||
|
assert.equal(id_to_windowname('misc-test'), 'misc__dash__test');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('windowname_to_id', function(assert) {
|
||||||
|
assert.equal(windowname_to_id('__dot__test'), '.test');
|
||||||
|
assert.equal(windowname_to_id('misc__dash__test'), 'misc-test');
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
module('admin.SelectBox');
|
||||||
|
|
||||||
|
test('init: no options', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
$('<select id="id"></select>').appendTo('#qunit-fixture');
|
||||||
|
SelectBox.init('id');
|
||||||
|
assert.equal(SelectBox.cache['id'].length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('filter', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
$('<select id="id"></select>').appendTo('#qunit-fixture');
|
||||||
|
$('<option value="0">A</option>').appendTo('#id');
|
||||||
|
$('<option value="1">B</option>').appendTo('#id');
|
||||||
|
SelectBox.init('id');
|
||||||
|
assert.equal($('#id option').length, 2);
|
||||||
|
SelectBox.filter('id', "A");
|
||||||
|
assert.equal($('#id option').length, 1);
|
||||||
|
assert.equal($('#id option').text(), "A");
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
module('admin.SelectFilter2');
|
||||||
|
|
||||||
|
test('init', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
$('<form><select id="id"></select></form>').appendTo('#qunit-fixture');
|
||||||
|
$('<option value="0">A</option>').appendTo('#id');
|
||||||
|
SelectFilter.init('id', 'things', 0);
|
||||||
|
assert.equal($('.selector-available h2').text().trim(), "Available things");
|
||||||
|
assert.equal($('.selector-chosen h2').text().trim(), "Chosen things");
|
||||||
|
assert.equal($('.selector-chooseall').text(), "Choose all");
|
||||||
|
assert.equal($('.selector-add').text(), "Choose");
|
||||||
|
assert.equal($('.selector-remove').text(), "Remove");
|
||||||
|
assert.equal($('.selector-clearall').text(), "Remove all");
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
module('admin.actions', {
|
||||||
|
beforeEach: function() {
|
||||||
|
// Number of results shown on page
|
||||||
|
window._actions_icnt = '100';
|
||||||
|
|
||||||
|
var $ = django.jQuery;
|
||||||
|
$('#qunit-fixture').append($('#result-table').text());
|
||||||
|
|
||||||
|
$('tr input.action-select').actions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('check', function(assert) {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
assert.notOk($('.action-select').is(':checked'));
|
||||||
|
$('#action-toggle').click();
|
||||||
|
assert.ok($('.action-select').is(':checked'));
|
||||||
|
});
|
|
@ -0,0 +1,59 @@
|
||||||
|
module('admin.core');
|
||||||
|
|
||||||
|
test('Date.getTwelveHours', function(assert) {
|
||||||
|
assert.equal(new Date(2011, 0, 1, 0, 0).getTwelveHours(), 12, '0:00');
|
||||||
|
assert.equal(new Date(2011, 0, 1, 11, 0).getTwelveHours(), 11, '11:00');
|
||||||
|
assert.equal(new Date(2011, 0, 1, 16, 0).getTwelveHours(), 4, '16:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitMonth', function(assert) {
|
||||||
|
assert.equal(new Date(2011, 0, 1).getTwoDigitMonth(), '01', 'jan 1');
|
||||||
|
assert.equal(new Date(2011, 9, 1).getTwoDigitMonth(), '10', 'oct 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitDate', function(assert) {
|
||||||
|
assert.equal(new Date(2011, 0, 1).getTwoDigitDate(), '01', 'jan 1');
|
||||||
|
assert.equal(new Date(2011, 0, 15).getTwoDigitDate(), '15', 'jan 15');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitTwelveHour', function(assert) {
|
||||||
|
assert.equal(new Date(2011, 0, 1, 0, 0).getTwoDigitTwelveHour(), '12', '0:00');
|
||||||
|
assert.equal(new Date(2011, 0, 1, 4, 0).getTwoDigitTwelveHour(), '04', '4:00');
|
||||||
|
assert.equal(new Date(2011, 0, 1, 22, 0).getTwoDigitTwelveHour(), '10', '22:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitHour', function(assert) {
|
||||||
|
assert.equal(new Date(2014, 6, 1, 9, 0).getTwoDigitHour(), '09', '9:00 am is 09');
|
||||||
|
assert.equal(new Date(2014, 6, 1, 11, 0).getTwoDigitHour(), '11', '11:00 am is 11');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitMinute', function(assert) {
|
||||||
|
assert.equal(new Date(2014, 6, 1, 0, 5).getTwoDigitMinute(), '05', '12:05 am is 05');
|
||||||
|
assert.equal(new Date(2014, 6, 1, 0, 15).getTwoDigitMinute(), '15', '12:15 am is 15');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getTwoDigitSecond', function(assert) {
|
||||||
|
assert.equal(new Date(2014, 6, 1, 0, 0, 2).getTwoDigitSecond(), '02', '12:00:02 am is 02');
|
||||||
|
assert.equal(new Date(2014, 6, 1, 0, 0, 20).getTwoDigitSecond(), '20', '12:00:20 am is 20');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getHourMinute', function(assert) {
|
||||||
|
assert.equal(new Date(2014, 6, 1, 11, 0).getHourMinute(), '11:00', '11:00 am is 11:00');
|
||||||
|
assert.equal(new Date(2014, 6, 1, 13, 25).getHourMinute(), '13:25', '1:25 pm is 13:25');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.getHourMinuteSecond', function(assert) {
|
||||||
|
assert.equal(new Date(2014, 6, 1, 11, 0, 0).getHourMinuteSecond(), '11:00:00', '11:00 am is 11:00:00');
|
||||||
|
assert.equal(new Date(2014, 6, 1, 17, 45, 30).getHourMinuteSecond(), '17:45:30', '5:45:30 pm is 17:45:30');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date.strftime', function(assert) {
|
||||||
|
var date = new Date(2014, 6, 1, 11, 0, 5);
|
||||||
|
assert.equal(date.strftime('%Y-%m-%d %H:%M:%S'), '2014-07-01 11:00:05');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('String.strptime', function(assert) {
|
||||||
|
var date = new Date(1988, 1, 26);
|
||||||
|
assert.equal('1988-02-26'.strptime('%Y-%m-%d').toString(), date.toString());
|
||||||
|
assert.equal('26/02/88'.strptime('%d/%m/%y').toString(), date.toString());
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
module('admin.inlines: tabular formsets', {
|
||||||
|
beforeEach: function() {
|
||||||
|
var $ = django.jQuery;
|
||||||
|
var that = this;
|
||||||
|
this.addText = 'Add another';
|
||||||
|
|
||||||
|
$('#qunit-fixture').append($('#tabular-formset').text());
|
||||||
|
this.table = $('table.inline');
|
||||||
|
this.inlineRow = this.table.find('tr');
|
||||||
|
that.inlineRow.tabularFormset({
|
||||||
|
prefix: 'first',
|
||||||
|
addText: that.addText,
|
||||||
|
deleteText: 'Remove'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no forms', function(assert) {
|
||||||
|
assert.ok(this.inlineRow.hasClass('dynamic-first'));
|
||||||
|
assert.equal(this.table.find('.add-row a').text(), this.addText);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('add form', function(assert) {
|
||||||
|
var addButton = this.table.find('.add-row a');
|
||||||
|
assert.equal(addButton.text(), this.addText);
|
||||||
|
addButton.click();
|
||||||
|
assert.ok(this.table.find('#first-1').hasClass('row2'));
|
||||||
|
});
|
|
@ -0,0 +1,82 @@
|
||||||
|
(function (globals) {
|
||||||
|
|
||||||
|
var django = globals.django || (globals.django = {});
|
||||||
|
|
||||||
|
django.pluralidx = function (count) { return (count == 1) ? 0 : 1; };
|
||||||
|
|
||||||
|
/* gettext identity library */
|
||||||
|
|
||||||
|
django.gettext = function (msgid) { return msgid; };
|
||||||
|
django.ngettext = function (singular, plural, count) { return (count == 1) ? singular : plural; };
|
||||||
|
django.gettext_noop = function (msgid) { return msgid; };
|
||||||
|
django.pgettext = function (context, msgid) { return msgid; };
|
||||||
|
django.npgettext = function (context, singular, plural, count) { return (count == 1) ? singular : plural; };
|
||||||
|
|
||||||
|
django.interpolate = function (fmt, obj, named) {
|
||||||
|
if (named) {
|
||||||
|
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
|
||||||
|
} else {
|
||||||
|
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* formatting library */
|
||||||
|
|
||||||
|
django.formats = {
|
||||||
|
"DATETIME_FORMAT": "N j, Y, P",
|
||||||
|
"DATETIME_INPUT_FORMATS": [
|
||||||
|
"%Y-%m-%d %H:%M:%S",
|
||||||
|
"%Y-%m-%d %H:%M:%S.%f",
|
||||||
|
"%Y-%m-%d %H:%M",
|
||||||
|
"%Y-%m-%d",
|
||||||
|
"%m/%d/%Y %H:%M:%S",
|
||||||
|
"%m/%d/%Y %H:%M:%S.%f",
|
||||||
|
"%m/%d/%Y %H:%M",
|
||||||
|
"%m/%d/%Y",
|
||||||
|
"%m/%d/%y %H:%M:%S",
|
||||||
|
"%m/%d/%y %H:%M:%S.%f",
|
||||||
|
"%m/%d/%y %H:%M",
|
||||||
|
"%m/%d/%y"
|
||||||
|
],
|
||||||
|
"DATE_FORMAT": "N j, Y",
|
||||||
|
"DATE_INPUT_FORMATS": [
|
||||||
|
"%Y-%m-%d",
|
||||||
|
"%m/%d/%Y",
|
||||||
|
"%m/%d/%y"
|
||||||
|
],
|
||||||
|
"DECIMAL_SEPARATOR": ".",
|
||||||
|
"FIRST_DAY_OF_WEEK": "0",
|
||||||
|
"MONTH_DAY_FORMAT": "F j",
|
||||||
|
"NUMBER_GROUPING": "3",
|
||||||
|
"SHORT_DATETIME_FORMAT": "m/d/Y P",
|
||||||
|
"SHORT_DATE_FORMAT": "m/d/Y",
|
||||||
|
"THOUSAND_SEPARATOR": ",",
|
||||||
|
"TIME_FORMAT": "P",
|
||||||
|
"TIME_INPUT_FORMATS": [
|
||||||
|
"%H:%M:%S",
|
||||||
|
"%H:%M:%S.%f",
|
||||||
|
"%H:%M"
|
||||||
|
],
|
||||||
|
"YEAR_MONTH_FORMAT": "F Y"
|
||||||
|
};
|
||||||
|
|
||||||
|
django.get_format = function (format_type) {
|
||||||
|
var value = django.formats[format_type];
|
||||||
|
if (typeof(value) == 'undefined') {
|
||||||
|
return format_type;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* add to global namespace */
|
||||||
|
globals.pluralidx = django.pluralidx;
|
||||||
|
globals.gettext = django.gettext;
|
||||||
|
globals.ngettext = django.ngettext;
|
||||||
|
globals.gettext_noop = django.gettext_noop;
|
||||||
|
globals.pgettext = django.pgettext;
|
||||||
|
globals.npgettext = django.npgettext;
|
||||||
|
globals.interpolate = django.interpolate;
|
||||||
|
globals.get_format = django.get_format;
|
||||||
|
|
||||||
|
}(this));
|
|
@ -0,0 +1,28 @@
|
||||||
|
module('admin.timeparse');
|
||||||
|
|
||||||
|
test('parseTimeString', function(assert) {
|
||||||
|
function time(then, expected) {
|
||||||
|
assert.equal(parseTimeString(then), expected);
|
||||||
|
}
|
||||||
|
time('9', '09:00');
|
||||||
|
time('09', '09:00');
|
||||||
|
time('13:00', '13:00');
|
||||||
|
time('13.00', '13:00');
|
||||||
|
time('9:00', '09:00');
|
||||||
|
time('9.00', '09:00');
|
||||||
|
time('3 am', '03:00');
|
||||||
|
time('3 a.m.', '03:00');
|
||||||
|
time('12 am', '00:00');
|
||||||
|
time('11 am', '11:00');
|
||||||
|
time('12 pm', '12:00');
|
||||||
|
time('3am', '03:00');
|
||||||
|
time('3.30 am', '03:30');
|
||||||
|
time('3:15 a.m.', '03:15');
|
||||||
|
time('3.00am', '03:00');
|
||||||
|
time('12.00am', '00:00');
|
||||||
|
time('11.00am', '11:00');
|
||||||
|
time('12.00pm', '12:00');
|
||||||
|
time('noon', '12:00');
|
||||||
|
time('midnight', '00:00');
|
||||||
|
time('something else', 'something else');
|
||||||
|
});
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,78 @@
|
||||||
|
// grunt-reporter.js
|
||||||
|
//
|
||||||
|
// A communication bridge between blanket.js and the grunt-blanket-qunit plugin
|
||||||
|
// Distributed as part of the grunt-blanket-qunit library
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 Model N, Inc.
|
||||||
|
// Distributed under the MIT License
|
||||||
|
//
|
||||||
|
// Documentation and full license available at:
|
||||||
|
// https://github.com/ModelN/grunt-blanket-qunit
|
||||||
|
//
|
||||||
|
(function (){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// this is an ugly hack, but it's the official way of communicating between
|
||||||
|
// the parent phantomjs and the inner grunt-contrib-qunit library...
|
||||||
|
var sendMessage = function sendMessage() {
|
||||||
|
var args = [].slice.call(arguments);
|
||||||
|
alert(JSON.stringify(args));
|
||||||
|
};
|
||||||
|
|
||||||
|
// helper function for computing coverage info for a particular file
|
||||||
|
var reportFile = function( data ) {
|
||||||
|
var ret = {
|
||||||
|
coverage: 0,
|
||||||
|
hits: 0,
|
||||||
|
misses: 0,
|
||||||
|
sloc: 0
|
||||||
|
};
|
||||||
|
for (var i = 0; i < data.source.length; i++) {
|
||||||
|
var line = data.source[i];
|
||||||
|
var num = i + 1;
|
||||||
|
if (data[num] === 0) {
|
||||||
|
ret.misses++;
|
||||||
|
ret.sloc++;
|
||||||
|
} else if (data[num] !== undefined) {
|
||||||
|
ret.hits++;
|
||||||
|
ret.sloc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret.coverage = ret.hits / ret.sloc * 100;
|
||||||
|
|
||||||
|
return [ret.hits,ret.sloc];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// this function is invoked by blanket.js when the coverage data is ready. it will
|
||||||
|
// compute per-file coverage info, and send a message to the parent phantomjs process
|
||||||
|
// for each file, which the grunt task will use to report passes & failures.
|
||||||
|
var reporter = function(cov){
|
||||||
|
cov = window._$blanket;
|
||||||
|
|
||||||
|
var sortedFileNames = [];
|
||||||
|
|
||||||
|
var totals =[];
|
||||||
|
|
||||||
|
for (var filename in cov) {
|
||||||
|
if (cov.hasOwnProperty(filename)) {
|
||||||
|
sortedFileNames.push(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedFileNames.sort();
|
||||||
|
|
||||||
|
for (var i = 0; i < sortedFileNames.length; i++) {
|
||||||
|
var thisFile = sortedFileNames[i];
|
||||||
|
var data = cov[thisFile];
|
||||||
|
var thisTotal= reportFile( data );
|
||||||
|
sendMessage("blanket:fileDone", thisTotal, thisFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage("blanket:done");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
blanket.customReporter = reporter;
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,291 @@
|
||||||
|
/*!
|
||||||
|
* QUnit 1.18.0
|
||||||
|
* http://qunitjs.com/
|
||||||
|
*
|
||||||
|
* Copyright jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* Date: 2015-04-03T10:23Z
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Font Family and Sizes */
|
||||||
|
|
||||||
|
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
|
||||||
|
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
|
||||||
|
#qunit-tests { font-size: smaller; }
|
||||||
|
|
||||||
|
|
||||||
|
/** Resets */
|
||||||
|
|
||||||
|
#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Header */
|
||||||
|
|
||||||
|
#qunit-header {
|
||||||
|
padding: 0.5em 0 0.5em 1em;
|
||||||
|
|
||||||
|
color: #8699A4;
|
||||||
|
background-color: #0D3349;
|
||||||
|
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 1em;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-header a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #C2CCD1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-header a:hover,
|
||||||
|
#qunit-header a:focus {
|
||||||
|
color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-testrunner-toolbar label {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0.5em 0 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-banner {
|
||||||
|
height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-testrunner-toolbar {
|
||||||
|
padding: 0.5em 1em 0.5em 1em;
|
||||||
|
color: #5E740B;
|
||||||
|
background-color: #EEE;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-userAgent {
|
||||||
|
padding: 0.5em 1em 0.5em 1em;
|
||||||
|
background-color: #2B81AF;
|
||||||
|
color: #FFF;
|
||||||
|
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-modulefilter-container {
|
||||||
|
float: right;
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qunit-url-config {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qunit-filter {
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tests: Pass/Fail */
|
||||||
|
|
||||||
|
#qunit-tests {
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li {
|
||||||
|
padding: 0.4em 1em 0.4em 1em;
|
||||||
|
border-bottom: 1px solid #FFF;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests > li {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li.running,
|
||||||
|
#qunit-tests li.pass,
|
||||||
|
#qunit-tests li.fail,
|
||||||
|
#qunit-tests li.skipped {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests.hidepass li.running,
|
||||||
|
#qunit-tests.hidepass li.pass {
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li strong {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li.skipped strong {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li a {
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #C2CCD1;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li p a {
|
||||||
|
padding: 0.25em;
|
||||||
|
color: #6B6464;
|
||||||
|
}
|
||||||
|
#qunit-tests li a:hover,
|
||||||
|
#qunit-tests li a:focus {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests li .runtime {
|
||||||
|
float: right;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qunit-assert-list {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
background-color: #FFF;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qunit-collapsed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests th {
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0 0.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests pre {
|
||||||
|
margin: 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests del {
|
||||||
|
background-color: #E0F2BE;
|
||||||
|
color: #374E0C;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests ins {
|
||||||
|
background-color: #FFCACA;
|
||||||
|
color: #500;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Test Counts */
|
||||||
|
|
||||||
|
#qunit-tests b.counts { color: #000; }
|
||||||
|
#qunit-tests b.passed { color: #5E740B; }
|
||||||
|
#qunit-tests b.failed { color: #710909; }
|
||||||
|
|
||||||
|
#qunit-tests li li {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #FFF;
|
||||||
|
border-bottom: none;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Passing Styles */
|
||||||
|
|
||||||
|
#qunit-tests li li.pass {
|
||||||
|
color: #3C510C;
|
||||||
|
background-color: #FFF;
|
||||||
|
border-left: 10px solid #C6E746;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
|
||||||
|
#qunit-tests .pass .test-name { color: #366097; }
|
||||||
|
|
||||||
|
#qunit-tests .pass .test-actual,
|
||||||
|
#qunit-tests .pass .test-expected { color: #999; }
|
||||||
|
|
||||||
|
#qunit-banner.qunit-pass { background-color: #C6E746; }
|
||||||
|
|
||||||
|
/*** Failing Styles */
|
||||||
|
|
||||||
|
#qunit-tests li li.fail {
|
||||||
|
color: #710909;
|
||||||
|
background-color: #FFF;
|
||||||
|
border-left: 10px solid #EE5757;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests > li:last-child {
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests .fail { color: #000; background-color: #EE5757; }
|
||||||
|
#qunit-tests .fail .test-name,
|
||||||
|
#qunit-tests .fail .module-name { color: #000; }
|
||||||
|
|
||||||
|
#qunit-tests .fail .test-actual { color: #EE5757; }
|
||||||
|
#qunit-tests .fail .test-expected { color: #008000; }
|
||||||
|
|
||||||
|
#qunit-banner.qunit-fail { background-color: #EE5757; }
|
||||||
|
|
||||||
|
/*** Skipped tests */
|
||||||
|
|
||||||
|
#qunit-tests .skipped {
|
||||||
|
background-color: #EBECE9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qunit-tests .qunit-skipped-label {
|
||||||
|
background-color: #F4FF77;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
color: #366097;
|
||||||
|
line-height: 1.8em;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
margin: -0.4em 0.4em -0.4em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Result */
|
||||||
|
|
||||||
|
#qunit-testresult {
|
||||||
|
padding: 0.5em 1em 0.5em 1em;
|
||||||
|
|
||||||
|
color: #2B81AF;
|
||||||
|
background-color: #D2E0E6;
|
||||||
|
|
||||||
|
border-bottom: 1px solid #FFF;
|
||||||
|
}
|
||||||
|
#qunit-testresult .module-name {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fixture */
|
||||||
|
|
||||||
|
#qunit-fixture {
|
||||||
|
position: absolute;
|
||||||
|
top: -10000px;
|
||||||
|
left: -10000px;
|
||||||
|
width: 1000px;
|
||||||
|
height: 1000px;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Django JavaScript Tests</title>
|
||||||
|
<link rel="stylesheet" href="./qunit/qunit.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<div id="qunit-fixture">
|
||||||
|
</div>
|
||||||
|
<script type="text/html" id="result-table">
|
||||||
|
<table id="result_list">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<input type="checkbox" id="action-toggle">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="action-checkbox">
|
||||||
|
<input class="action-select" type="checkbox" value="618">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="tabular-formset">
|
||||||
|
<input id="id_first-TOTAL_FORMS" value="1">
|
||||||
|
<input id="id_first-MAX_NUM_FORMS" value="">
|
||||||
|
<table class="inline">
|
||||||
|
<tr id="first-0" class="form-row">
|
||||||
|
<td class="field-test_field">
|
||||||
|
<input id="id_first-test_field">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="first-empty" class="empty-row">
|
||||||
|
<td class="field-test_field">
|
||||||
|
<input id="id_first-test_field">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="./qunit/qunit.js"></script>
|
||||||
|
<script src="./qunit/blanket.min.js" data-cover-flags="branchTracking"></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/vendor/jquery/jquery.min.js'></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/jquery.init.js'></script>
|
||||||
|
<script src='./admin/jsi18n-mocks.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/core.js' data-cover></script>
|
||||||
|
<script src='./admin/core.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/timeparse.js' data-cover></script>
|
||||||
|
<script src='./admin/timeparse.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js' data-cover></script>
|
||||||
|
<script src='./admin/RelatedObjectLookups.test.js'></script>
|
||||||
|
|
||||||
|
<script src='./admin/DateTimeShortcuts.test.js'></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/calendar.js' data-cover></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js' data-cover></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/actions.js' data-cover></script>
|
||||||
|
<script src='./admin/actions.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/SelectBox.js' data-cover></script>
|
||||||
|
<script src='./admin/SelectBox.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/SelectFilter2.js' data-cover></script>
|
||||||
|
<script src='./admin/SelectFilter2.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/inlines.js' data-cover></script>
|
||||||
|
<script src='./admin/inlines.test.js'></script>
|
||||||
|
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/actions.js' data-cover></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/collapse.js' data-cover></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/prepopulate.js' data-cover></script>
|
||||||
|
<script src='../django/contrib/admin/static/admin/js/urlify.js' data-cover></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if (location.href.match(/(\?|&)gruntReport($|&|=)/)) {
|
||||||
|
blanket.options("reporter", "qunit/grunt-reporter.js");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -2,9 +2,13 @@
|
||||||
"name": "Django",
|
"name": "Django",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pretest": "eslint django/"
|
"pretest": "eslint django/",
|
||||||
|
"test": "grunt test --verbose"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^0.22.1"
|
"eslint": "^0.22.1",
|
||||||
|
"grunt": "^0.4.5",
|
||||||
|
"grunt-blanket-qunit": "^0.2.0",
|
||||||
|
"grunt-cli": "^0.1.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue