Skip to content

Instantly share code, notes, and snippets.

@insin
Last active August 29, 2015 14:00
Show Gist options
  • Save insin/11125180 to your computer and use it in GitHub Desktop.
Save insin/11125180 to your computer and use it in GitHub Desktop.
QUnit test starter example
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.14.0.css">
<script src="//code.jquery.com/qunit/qunit-1.14.0.js"></script>
<script src="SortableTable.js"></script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<div style="display: none;">
<table id="basic-sorting">
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
</tr>
</tbody>
</thead>
</div>
<script src="tests.js"></script>
</body>
</html>
void function () {
'use strict';
var SortableTable = {
//Initialize
init: function (element) {
this.table = element;
this.header = this.table.getElementsByTagName('thead')[0];
this.headerLength = this.header.children.length;
this.columnIndex = -1;
this.readTableData(this.table);
this.userInteraction();
},
//Convert the table into an array
readTableData: function (table) {
var rowLength, cellLength, columnHeaders, tableData, rowCellLength, tableRow, rowData, i, j;
rowLength = table.rows.length;
cellLength = table.rows[0].cells.length;
columnHeaders = [];
tableData = [];
for (i = 0; i < cellLength; i++) {
columnHeaders[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi, '');
}
for (i = 1; i < rowLength; i++) {
tableRow = table.rows[i];
rowCellLength = tableRow.cells.length;
rowData = {};
for (j = 0; j < rowCellLength; j++) {
rowData[columnHeaders[j]] = tableRow.cells[j].innerHTML;
}
tableData.push(rowData);
}
return tableData;
},
//Control what happens when user interacts
userInteraction: function () {
var tableHeaders, sortDirection, i, j;
this.header.addEventListener('click', function (e) {
if (e.target.tagName.toLowerCase() === 'th') {
tableHeaders = e.target.parentNode.children;
SortableTable.activeHeader = e.target;
SortableTable.columnIndex = Array.prototype.indexOf.call(tableHeaders, e.target);
if (SortableTable.columnIndex == SortableTable.table.getAttribute('data-sortedindex')) {
if (SortableTable.table.getAttribute('data-sortdirection') == 'asc') {
SortableTable.table.setAttribute('data-sortdirection', 'desc');
} else { SortableTable.table.setAttribute('data-sortdirection', 'asc'); }
} else { SortableTable.table.setAttribute('data-sortdirection', 'asc'); }
sortDirection = SortableTable.table.getAttribute('data-sortdirection');
SortableTable.rowSort(sortDirection);
SortableTable.table.setAttribute('data-sortedindex', SortableTable.columnIndex);
for (i = 0; i < SortableTable.headerLength; i++) {
for (j = 0; j < tableHeaders.length; j++) {
tableHeaders[j].className = '';
}
}
SortableTable.activeHeader.className = 'active';
}
}, false);
},
//Sort the table array in memory
rowSort: function (direction) {
var newRows, cellIndex, rowParent, i;
newRows = [];
cellIndex = 0;
for (i = 1; i < this.table.rows.length; i++) {
rowParent = this.table.rows[i].parentNode.tagName.toLowerCase();
if (rowParent === 'tbody') {
newRows[cellIndex] = this.table.rows[i];
newRows[cellIndex].initialIndex = cellIndex;
cellIndex++;
}
}
if (newRows.length === 0) { return; }
newRows.sort(this.rowCompare);
if (direction === 'desc') {
newRows.reverse();
}
this.updateTable(this.table, newRows);
},
//Compare rows based on current columnIndex
rowCompare: function (a, b) {
var rowA, rowB;
rowA = a.cells[SortableTable.columnIndex].innerHTML.toLowerCase();
rowB = b.cells[SortableTable.columnIndex].innerHTML.toLowerCase();
if (rowA === rowB) { return 0; }
if (rowA < rowB) { return -1; }
return 1;
},
//Replace the table rows with the rows from the table array
updateTable: function (table, newRows) {
var i;
for (i = 0; i < newRows.length; i++) {
table.tBodies[0].appendChild(newRows[i]);
}
}
};
window.SortableTable = SortableTable;
}();
QUnit.module('SortableTable');
function setupFixture(id) {
var table = document.getElementById(id).cloneNode(true);
document.getElementById('qunit-fixture').appendChild(table);
return table;
}
function click(el) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); // LOL
el.dispatchEvent(evt);
}
function dumpTable(table) {
return [].map.call(table.querySelectorAll('tbody tr'), function(tr) {
return [].map.call(tr.querySelectorAll('td'), function(td) {
return td.textContent;
})
});
}
QUnit.test('basic sorting', function() {
// CREATE STUFF: Setup a test fixture table to test against
var table = setupFixture('basic-sorting');
SortableTable.init(table);
// ASSERT STUFF: Use assertion functions to assert stuff which should now be true about the state of 'table' and 'SortableTable'
// e.g. table header class names, data-sortdirection attribute
// Ref: http://api.qunitjs.com/category/assert/
strictEqual(SortableTable.table, table);
// TODO This next test fails - fix your code :)
equal(SortableTable.headerLength, 2, 'There are 2 headings in the test table');
// DO STUFF: Trigger a click event on the Col 2 heading
click(table.querySelectorAll('th')[1]);
// ASSERT STUFF: Pull table content and assert it's sorted as expected
deepEqual(dumpTable(table), [
['3', '1']
, ['2', '2']
, ['1', '3']
], 'The table should be sorted by column 2 in ascending order');
// TODO Assert other stuff that should be true after a sort has been performed
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment