From 7af6bf7a986e6c9c306e5f5acf6481c26b82f022 Mon Sep 17 00:00:00 2001 From: David Morse Date: Sun, 12 Apr 2015 23:26:19 -0600 Subject: [PATCH] Add unit testing for core API, ensure all demos work, and add unit testing to ensure they stay working. --- demos/expandable-widgets.html | 7 +- demos/grid-from-serialize.html | 56 +- demos/resize-limits.html | 12 +- demos/resize.html | 2 +- dist/jquery.gridster.css | 2 +- dist/jquery.gridster.js | 7609 +++++++++++----------- dist/jquery.gridster.min.css | 2 +- dist/jquery.gridster.min.js | 4 +- dist/jquery.gridster.with-extras.js | 7641 ++++++++++++----------- dist/jquery.gridster.with-extras.min.js | 4 +- src/jquery.gridster.extras.js | 32 +- src/jquery.gridster.js | 7607 +++++++++++----------- test/jquery.gridster.html | 76 +- test/jquery.gridster_test.js | 453 +- 14 files changed, 11982 insertions(+), 11525 deletions(-) diff --git a/demos/expandable-widgets.html b/demos/expandable-widgets.html index 19d591ece2..d618b3294e 100644 --- a/demos/expandable-widgets.html +++ b/demos/expandable-widgets.html @@ -41,21 +41,20 @@ - + + gridster.js Test Suite + + + - + + + + + + + - + + + - - - - - - + + -

gridster.js Test Suite

-

-
-

-
    -
    +

    gridster.js Test Suite

    -
    -
      -
    • -
    • -
    • -
    • +

      -
    • -
    • -
    • -
    • -
    • +
      +

      +
        +
        -
      1. - - -
      2. -
      3. -
      4. -
      5. - -
      6. -
      7. - -
      8. - -
      +
      +
        +
      • +
      • +
      -
      -
      +
      +
      diff --git a/test/jquery.gridster_test.js b/test/jquery.gridster_test.js index f0c8351f7e..10d980335d 100644 --- a/test/jquery.gridster_test.js +++ b/test/jquery.gridster_test.js @@ -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('
    • ', 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('
    • ', 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('
    • ', 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('
    • ', 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('
    • ', 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('
    • ', 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('
    • ', 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('
    • ', 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)); \ No newline at end of file