Add unit testing for core API, ensure all demos work, and add unit testing to ensure they stay working.

This commit is contained in:
David Morse
2015-04-12 23:26:19 -06:00
parent 385cc757ac
commit 7af6bf7a98
14 changed files with 11982 additions and 11525 deletions

View File

@ -1,62 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>gridster.js Test Suite</title>
<!-- Load local jQuery, removing access to $ (use jQuery, not $). -->
<script src="../libs/jquery/jquery.js"></script>
<script>jQuery.noConflict()</script>
<meta charset="utf-8">
<title>gridster.js Test Suite</title>
<!-- Load JQuery dependency. -->
<script src="../libs/jquery/jquery.js"></script>
<script>jQuery.noConflict()</script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<!-- load the gridster source files, run the tests against the broken out javascipt in the source dir-->
<script src="../src/jquery.coords.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.collision.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/utils.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.draggable.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.gridster.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="../src/jquery.gridster.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.css">
<!-- Load QUnit dependency. -->
<link rel="stylesheet" href="../libs/qunit/qunit/qunit.css" media="screen">
<script src="../libs/qunit/qunit/qunit.js"></script>
<!-- Load local QUnit (grunt requires v1.0.0 or newer). -->
<link rel="stylesheet" href="../libs/qunit/qunit/qunit.css" media="screen">
<script src="../libs/qunit/qunit/qunit.js"></script>
<!-- Load local lib and tests. -->
<script src="jquery.gridster_test.js"></script>
<!-- Load local lib and tests. -->
<script src="jquery.gridster_test.js"></script>
</head>
<body>
<h1 id="qunit-header">gridster.js Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">
<h1 id="qunit-header">gridster.js Test Suite</h1>
<div class="wrapper">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2"></li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2"></li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1"></li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1"></li>
<h2 id="qunit-banner"></h2>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1"></li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1"></li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1"></li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1"></li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1"></li>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3"></li>
<li data-row="5" data-col="1" data-sizex="1" data-sizey="2"></li>
<li data-row="4" data-col="3" data-sizex="1" data-sizey="2"></li>
<li data-row="5" data-col="4" data-sizex="1" data-sizey="1"></li>
<li data-row="6" data-col="2" data-sizex="3" data-sizey="1"></li>
<li data-row="4" data-col="5" data-sizex="1" data-sizey="2"></li>
<li data-row="6" data-col="5" data-sizex="1" data-sizey="1"></li>
<li data-row="7" data-col="3" data-sizex="1" data-sizey="1"></li>
</ul>
<div class="wrapper">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2"></li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2"></li>
</ul>
</div>
</div>
<div id="qunit-testresult"></div>
</div>
<div id="qunit-testresult"></div>
</body>
</html>

View File

@ -1,128 +1,373 @@
/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/
(function($) {
(function ($) {
/*
======== A Handy Little QUnit Reference ========
http://docs.jquery.com/QUnit
/*
======== A Handy Little QUnit Reference ========
http://docs.jquery.com/QUnit
Test methods:
expect(numAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
raises(block, [expected], [message])
*/
Test methods:
expect(numAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
raises(block, [expected], [message])
*/
module('jQuery#gridster', {
setup: function() {
module('jQuery#gridster', {
setup: function () {
this.el = $('#qunit-fixture').find(".wrapper ul");
this.el = $('#qunit-fixture').find(".wrapper ul");
this.serialization = [
{ name: "A", col: "1", row: "1", size_x: "2", size_y: "2" },
{ name: "B", col: "4", row: "1", size_x: "1", size_y: "2" },
{ name: "C", col: "10", row: "10", size_x: "10", size_y: "10" },
{ name: "D", col: "3", row: "1", size_x: "1", size_y: "1" },
{ name: "E", col: "2", row: "3", size_x: "3", size_y: "1" }
];
}
});
this.serialization = [
{name: "A", col: "1", row: "1", size_x: "2", size_y: "2"},
{name: "B", col: "4", row: "1", size_x: "1", size_y: "2"},
{name: "C", col: "10", row: "10", size_x: "10", size_y: "10"},
{name: "D", col: "3", row: "1", size_x: "1", size_y: "1"},
{name: "E", col: "2", row: "3", size_x: "3", size_y: "1"}
];
test('is chainable', 1, function() {
// Not a bad test to run on collection methods.
strictEqual(this.el, this.el.gridster(), 'should be chaninable');
});
this.serialization_small = [
{col: 1, row: 1, size_x: 2, size_y: 2},
{col: 3, row: 1, size_x: 1, size_y: 2},
{col: 6, row: 1, size_x: 1, size_y: 1}
];
}
});
test('Gridster.sort_by_row_asc', function(assert) {
var sorted = Gridster.sort_by_row_asc(this.serialization);
test('can count and clear widgets', 2, function () {
var grid = this.el.gridster().data('gridster');
equal(grid.get_num_widgets(), 2, 'Count the default widgets from the HTML config');
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
});
var result = pickup(sorted, 'name').join(',');
var expected = 'A,B,D,E,C';
assert.equal(result, expected);
});
test('Above and below', 12, function () {
var grid = this.el.gridster({ max_cols: 4, max_rows: 4, widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.serialization, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), this.serialization.length, 'Loaded the widgets for the test');
var widgets_above = $([]);
//the call here checks above as the user see's it on the screen which will check row below 4
grid.for_each_widget_above(3, 4, function(tcol, trow) {
widgets_above = widgets_above.add(this);
});
//widgets B (3,1) & E (2-4, 3) should be below cell 3,4
equal(2, widgets_above.length);
var widgets_found_above = grid.serialize(widgets_above);
equal(widgets_found_above[1].col, parseInt(this.serialization[4].col));
equal(widgets_found_above[1].row, parseInt(this.serialization[4].row));
equal(widgets_found_above[1].size_x, parseInt(this.serialization[4].size_x));
equal(widgets_found_above[1].size_y, parseInt(this.serialization[4].size_y));
test('Gridster.sort_by_row_and_col_asc', function(assert) {
var sorted = Gridster.sort_by_row_and_col_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,D,B,E,C';
assert.equal(result, expected);
});
var widgets_below = $([]);
grid.for_each_widget_below(3, 2, function(tcol, trow) {
widgets_below = widgets_below.add(this);
});
//widget E (2-4, 3) should be above cell 3,2
equal(1, widgets_below.length);
var widgets_found_below = grid.serialize(widgets_below);
equal(widgets_found_below[0].col, parseInt(this.serialization[4].col));
equal(widgets_found_below[0].row, parseInt(this.serialization[4].row));
equal(widgets_found_below[0].size_x, parseInt(this.serialization[4].size_x));
equal(widgets_found_below[0].size_y, parseInt(this.serialization[4].size_y));
});
test('Gridster.sort_by_col_asc', function(assert) {
var sorted = Gridster.sort_by_col_asc(this.serialization);
test('get_widgets_from', 5, function () {
var input = {col: 2, row: 1, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input.size_x, input.size_y, input.col, input.row);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,E,D,B,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_row_desc', function(assert) {
var sorted = Gridster.sort_by_row_desc(this.serialization);
var widget = grid.get_widgets_at_cell(input.col, input.row);
// normally you would call parseInt on a return from
// .attr(), but qunit takes care of it for us
equal(widget.attr('data-row'), input.row);
equal(widget.attr('data-col'), input.col);
equal(widget.attr('data-sizex'), input.size_x);
equal(widget.attr('data-sizey'), input.size_y);
});
var result = pickup(sorted, 'name').join(',');
var expected = 'C,E,A,B,D';
assert.equal(result, expected);
});
test('get_cells_occupied', 3, function () {
var input = {col: 2, row: 3, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
// erros
test('Throws not exists property', function(assert) {
assert.throws(function() {
var data = [{row:1, size_x:1, size_y:1},{col:2,row:1,size_x:1,size_y:1}];
Gridster.sort_by_row_asc(data);
},
Error,
'raise error not exists required property'
);
});
var cellsUsed = grid.get_cells_occupied(input);
deepEqual(cellsUsed.rows, [3]);
deepEqual(cellsUsed.cols, [2,3,4]);
});
test('Throws invalid type of value', function(assert) {
// inconvertible types
assert.throws(function() {
Gridster.sort_by_row_asc([{col:"AAA", row:1, size_x:1, size_y:1},{col:2,row:1,size_x:1,size_y:1}]);
},
Error,
'raise error inconvertible types'
);
test('get_highest_occupied_cell', 1, function () {
var input = {col: 2, row: 3, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
deepEqual(grid.get_min_col(), 1);
});
// null
assert.throws(function() {
Gridster.sort_by_row_asc([{col:null, row:1, size_x:1, size_y:1},{col:2,row:1,size_x:1,size_y:1}]);
},
Error,
'raise error value is null'
);
test('get_highest_occupied_cell', 1, function () {
var input = {col: 2, row: 3, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
deepEqual(grid.get_highest_occupied_cell(), {col: 3, row: 2});
});
// array
assert.throws(function() {
Gridster.sort_by_row_asc([{col:[1,2,3], row:1, size_x:1, size_y:1},{col:2,row:1,size_x:1,size_y:1}]);
},
Error,
'raise error value is array'
);
//todo tests to add:
// setup_resize & add_resize_handle
// get_min_col
// shift_cols
// get_widgets_from_DOM dom_to_coords, get_widgets_from_DOM set_dom_grid_height set_dom_grid_width
// generate_stylesheet
// set_num_columns
// object
assert.throws(function() {
Gridster.sort_by_row_asc([{col:{k:1}, row:1, size_x:1, size_y:1},{col:2,row:1,size_x:1,size_y:1}]);
},
Error,
'raise error value is object'
);
});
// helper
function pickup(data, prop) {
return data.map(function(elm) {
return elm[prop];
});
}
test('add_style_tag', 4, function () {
var grid = this.el.gridster({autogenerate_stylesheet: true}).data('gridster');
var generatedStyleSheet = $('#gridster-stylesheet');
notEqual(generatedStyleSheet, null);
ok(generatedStyleSheet.length > 0);
grid.destroy();
grid = this.el.gridster({autogenerate_stylesheet: true, namespace: 'qunit'}).data('gridster');
generatedStyleSheet = $('#gridster-stylesheet-qunit');
notEqual(generatedStyleSheet, null);
ok(generatedStyleSheet.length > 0);
});
test('resize_widget', 4, function () {
this.resizeGrid = [
{col: 1, row: 1, size_x: 1, size_y: 1},
{col: 2, row: 1, size_x: 1, size_y: 1},
{col: 3, row: 1, size_x: 1, size_y: 1},
{col: 1, row: 2, size_x: 1, size_y: 1},
{col: 2, row: 2, size_x: 1, size_y: 1},
{col: 3, row: 2, size_x: 1, size_y: 1},
{col: 1, row: 3, size_x: 1, size_y: 1},
{col: 2, row: 3, size_x: 1, size_y: 1},
{col: 3, row: 3, size_x: 1, size_y: 1}
];
var grid = this.el.gridster({widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
var numBefore = grid.get_num_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.resizeGrid, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), numBefore + this.resizeGrid.length, 'Loading the widgets to prepare for tests');
var row, col;
//check for widgets in the space it will occupy
var widgets = grid.get_widgets_in_range(1,1,2,2);
var numberInSpaceBefore = widgets.length;
equal(numberInSpaceBefore, 4, 'Expect there to be four widgets in the first two rows and cols');
//get the widget from 1,1 and resize it.
grid.resize_widget(grid.get_widgets_at_cell(1, 1), 2, 2);
//check for widgets in the space it will occupy
widgets = grid.get_widgets_in_range(1,1,2,2);
var numberInSpaceAfter = widgets.length;
equal(numberInSpaceAfter, 1, 'Expected a single widget in the expanded area');
});
test('can serialize correctly', 4, function () {
var grid = this.el.gridster({widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
var numBefore = grid.get_num_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.serialization_small, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), numBefore + this.serialization_small.length);
var serialized = grid.serialize();
equal(grid.get_num_widgets(), serialized.length);
deepEqual(serialized, this.serialization_small);
});
test('can serialize extended properties', 4, function () {
var input = [{col: 6, row: 3, size_x: 1, size_y: 1}];
var grid = this.el.gridster({widget_base_dimensions: [100, 55], serialize_params: function($w, wgd) {
return {
col: wgd.col,
row: wgd.row
};}}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
//due to custom serialization, input and output should NOT match
notDeepEqual(serialized, input);
equal(serialized[0].col, 6);
equal(serialized[0].size_x, undefined);
});
test('When Adding widgets rows auto condense', 2, function () {
var input = [{col: 6, row: 3, size_x: 1, size_y: 1}];
var output = [{col: 6, row: 1, size_x: 1, size_y: 1}];
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
//make sure we are empty
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
deepEqual(serialized, output);
});
test('When Adding widgets cols are respected', 2, function () {
var input = [{col: 6, row: 1, size_x: 1, size_y: 1}];
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
//make sure we are empty
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
deepEqual(serialized, input);
});
test('can_move_to', 7, function () {
var input = {col: 6, row: 1, size_x: 1, size_y: 1};
var defaultGrid = this.el.gridster().data('gridster');
//remove any widgets from the html config
defaultGrid.remove_all_widgets();
//make sure we are empty
equal(defaultGrid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
//check with the default config we can place an widget in a skipped col
var canMove = defaultGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row);
equal(canMove, true, 'with the default config we can place an widget in a skipped col');
//check with the default config we can not place an widget in a skipped row
canMove = defaultGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row+3);
equal(canMove, true, 'with the default config we can not place an widget in a skipped row');
defaultGrid.destroy();
//now repeat the tests with custom settings
var customGrid = this.el.gridster({max_rows : 2, max_cols : 4}).data('gridster');
//remove any widgets from the html config
customGrid.remove_all_widgets();
//make sure we are empty
equal(customGrid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
//check with the Custom config we can place an widget outside the grid
canMove = customGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row);
equal(canMove, false, 'with the Custom config we can place an widget outside the grid');
//check with the custom config we can not place an widget outside the grid
canMove = customGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, 1, input.row+3);
equal(canMove, false, 'with the custom config we can not place an widget outside the grid');
//check to see if we can't move an widget to where there is one
customGrid.add_widget('<li />', 1, 1, 1, 1);
canMove = customGrid.can_move_to({size_x: 1, size_y: 1}, 1, 1);
equal(canMove, false, 'we cant move an widget to where there is one');
});
test('is chainable', 1, function () {
// Not a bad test to run on collection methods.
strictEqual(this.el, this.el.gridster(), 'should be chaninable');
});
test('is Responsive', 1, function () {
var grid = this.el.gridster(
{autogenerate_stylesheet: true,
widget_base_dimensions: ['auto', 'auto'],
max_cols: 4}).data('gridster');
equal(grid.is_responsive(), true);
});
test('Gridster.sort_by_row_asc', function (assert) {
var sorted = Gridster.sort_by_row_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,B,D,E,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_row_and_col_asc', function (assert) {
var sorted = Gridster.sort_by_row_and_col_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,D,B,E,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_col_asc', function (assert) {
var sorted = Gridster.sort_by_col_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,E,D,B,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_row_desc', function (assert) {
var sorted = Gridster.sort_by_row_desc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'C,E,A,B,D';
assert.equal(result, expected);
});
// errors
test('sort_by_row_asc: Throws not exists property', function (assert) {
assert.throws(function () {
//missing col
var data = [{row: 1, size_x: 1, size_y: 1}, {col: 2, row: 1, size_x: 1, size_y: 1}];
Gridster.sort_by_row_asc(data);
},
Error,
'raise error not exists required property'
);
});
test('sort_by_row_asc: Throws invalid type of value', function (assert) {
var secWidget = {col: 2, row: 1, size_x: 1, size_y: 1};
// inconvertible types
assert.throws(function () {
//col is not a number
Gridster.sort_by_row_asc([{col: "AAA", row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error inconvertible types' );
// null
assert.throws(function () {
// coll is null
Gridster.sort_by_row_asc([{col: null, row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error value is null' );
// array
assert.throws(function () {
//col does not accept an array
Gridster.sort_by_row_asc([{col: [1, 2, 3], row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error value is array' );
// object
assert.throws(function () {
//col does not accept an onbject
Gridster.sort_by_row_asc([{col: {k: 1}, row: 1, size_x: 1, size_y: 1}, secWidget]);
},Error, 'raise error value is object');
});
// helper
function pickup (data, prop) {
return data.map(function (elm) {
return elm[prop];
});
}
}(jQuery));