4 wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
5 wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
6 wgDefaultDateFormat: 'dmy',
7 wgContentLanguage: 'en'
10 module( 'jquery.tablesorter', QUnit.newMwEnvironment({ config: config }) );
12 test( '-- Initial check', function() {
14 ok( $.tablesorter, '$.tablesorter defined' );
18 * Create an HTML table from an array of row arrays containing text strings.
19 * First row will be header row. No fancy rowspan/colspan stuff.
21 * @param {String[]} header
22 * @param {String[][]} data
25 var tableCreate = function( header, data ) {
26 var $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
27 $thead = $table.find( 'thead' ),
28 $tbody = $table.find( 'tbody' ),
31 $.each( header, function( i, str ) {
32 var $th = $( '<th>' );
33 $th.text( str ).appendTo( $tr );
35 $tr.appendTo( $thead );
37 for (var i = 0; i < data.length; i++) {
39 $.each( data[i], function( j, str ) {
40 var $td = $( '<td>' );
41 $td.text( str ).appendTo( $tr );
43 $tr.appendTo( $tbody );
49 * Extract text from table.
51 * @param {jQuery} $table
54 var tableExtract = function( $table ) {
57 $table.find( 'tbody' ).find( 'tr' ).each( function( i, tr ) {
59 $( tr ).find( 'td,th' ).each( function( i, td ) {
60 row.push( $( td ).text() );
68 * Run a table test by building a table with the given data,
69 * running some callback on it, then checking the results.
71 * @param {String} msg text to pass on to qunit for the comparison
72 * @param {String[]} header cols to make the table
73 * @param {String[][]} data rows/cols to make the table
74 * @param {String[][]} expected rows/cols to compare against at end
75 * @param {function($table)} callback something to do with the table before we compare
77 var tableTest = function( msg, header, data, expected, callback ) {
78 test( msg, function() {
81 var $table = tableCreate( header, data );
83 // Give caller a chance to set up sorting and manipulate the table.
86 // Table sorting is done synchronously; if it ever needs to change back
87 // to asynchronous, we'll need a timeout or a callback here.
88 var extracted = tableExtract( $table );
89 deepEqual( extracted, expected, msg );
93 var reversed = function(arr) {
94 var arr2 = arr.slice(0);
99 // Sample data set using planets named and their radius
100 var header = [ 'Planet' , 'Radius (km)'],
101 mercury = [ 'Mercury', '2439.7' ],
102 venus = [ 'Venus' , '6051.8' ],
103 earth = [ 'Earth' , '6371.0' ],
104 mars = [ 'Mars' , '3390.0' ],
105 jupiter = [ 'Jupiter', '69911' ],
106 saturn = [ 'Saturn' , '58232' ];
109 var planets = [mercury, venus, earth, mars, jupiter, saturn];
110 var ascendingName = [earth, jupiter, mars, mercury, saturn, venus];
111 var ascendingRadius = [mercury, mars, venus, earth, saturn, jupiter];
114 'Basic planet table: ascending by name',
119 $table.tablesorter();
120 $table.find( '.headerSort:eq(0)' ).click();
124 'Basic planet table: ascending by name a second time',
129 $table.tablesorter();
130 $table.find( '.headerSort:eq(0)' ).click();
134 'Basic planet table: descending by name',
137 reversed(ascendingName),
139 $table.tablesorter();
140 $table.find( '.headerSort:eq(0)' ).click().click();
144 'Basic planet table: ascending radius',
149 $table.tablesorter();
150 $table.find( '.headerSort:eq(1)' ).click();
154 'Basic planet table: descending radius',
157 reversed(ascendingRadius),
159 $table.tablesorter();
160 $table.find( '.headerSort:eq(1)' ).click().click();
167 'Bug 28775: German-style (dmy) short numeric dates',
169 [ // German-style dates are day-month-year
176 [ // Sorted by ascending date
184 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
185 mw.config.set( 'wgContentLanguage', 'de' );
187 $table.tablesorter();
188 $table.find( '.headerSort:eq(0)' ).click();
193 'Bug 28775: American-style (mdy) short numeric dates',
195 [ // American-style dates are month-day-year
202 [ // Sorted by ascending date
210 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
212 $table.tablesorter();
213 $table.find( '.headerSort:eq(0)' ).click();
218 // Some randomly generated fake IPs
229 // Sort order should go octet by octet
241 'Bug 17141: IPv4 address sorting',
246 $table.tablesorter();
247 $table.find( '.headerSort:eq(0)' ).click();
251 'Bug 17141: IPv4 address sorting (reverse)',
254 reversed(ipv4Sorted),
256 $table.tablesorter();
257 $table.find( '.headerSort:eq(0)' ).click().click();
262 // Some words with Umlauts
273 var umlautWordsSorted = [
274 // Some words with Umlauts
286 'Accented Characters with custom collation',
291 mw.config.set( 'tableSorterCollation', {
298 $table.tablesorter();
299 $table.find( '.headerSort:eq(0)' ).click();
303 var planetsRowspan = [["Earth","6051.8"], jupiter, ["Mars","6051.8"], mercury, saturn, venus];
304 var planetsRowspanII = [jupiter, mercury, saturn, ['Venus', '6371.0'], venus, ['Venus', '3390.0']];
307 'Basic planet table: same value for multiple rows via rowspan',
312 // Modify the table to have a multiuple-row-spanning cell:
313 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
314 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
315 // - Set rowspan for 2nd cell of 3rd row to 3.
316 // This covers the removed cell in the 4th and 5th row.
317 $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
319 $table.tablesorter();
320 $table.find( '.headerSort:eq(0)' ).click();
324 'Basic planet table: Same value for multiple rows via rowspan II',
329 // Modify the table to have a multiuple-row-spanning cell:
330 // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
331 $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
332 // - Set rowspan for 1st cell of 3rd row to 3.
333 // This covers the removed cell in the 4th and 5th row.
334 $table.find( 'tr:eq(2) td:eq(0)' ).prop( 'rowspan', '3' );
336 $table.tablesorter();
337 $table.find( '.headerSort:eq(0)' ).click();
341 var complexMDYDates = [
342 // Some words with Umlauts
343 ['January, 19 2010'],
350 var complexMDYSorted = [
354 ["January, 19 2010"],
359 'Complex date parsing I',
364 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
366 $table.tablesorter();
367 $table.find( '.headerSort:eq(0)' ).click();
371 var ascendingNameLegacy = ascendingName.slice(0);
372 ascendingNameLegacy[4] = ascendingNameLegacy[5];
373 ascendingNameLegacy.pop();
376 'Legacy compat with .sortbottom',
381 $table.find( 'tr:last' ).addClass( 'sortbottom' );
382 $table.tablesorter();
383 $table.find( '.headerSort:eq(0)' ).click();
387 /** FIXME: the diff output is not very readeable. */
388 test( 'bug 32047 - caption must be before thead', function() {
391 '<table class="sortable">' +
392 '<caption>CAPTION</caption>' +
393 '<tr><th>THEAD</th></tr>' +
394 '<tr><td>A</td></tr>' +
395 '<tr><td>B</td></tr>' +
396 '<tr class="sortbottom"><td>TFOOT</td></tr>' +
399 $table.tablesorter();
402 $table.children( ).get( 0 ).nodeName,
404 'First element after <thead> must be <caption> (bug 32047)'
408 test( 'data-sort-value attribute, when available, should override sorting position', function() {
411 // Simple example, one without data-sort-value which should be sorted at it's text.
413 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
415 '<tr><td>Cheetah</td></tr>' +
416 '<tr><td data-sort-value="Apple">Bird</td></tr>' +
417 '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
418 '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
419 '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
422 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
425 $table.find( 'tbody > tr' ).each( function( i, tr ) {
426 $( tr ).find( 'td' ).each( function( i, td ) {
427 data.push( { data: $( td ).data( 'sort-value' ), text: $( td ).text() } );
452 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
454 '<tr><td>D</td></tr>' +
455 '<tr><td data-sort-value="E">A</td></tr>' +
456 '<tr><td>B</td></tr>' +
457 '<tr><td>G</td></tr>' +
458 '<tr><td data-sort-value="F">C</td></tr>' +
461 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
464 $table.find( 'tbody > tr' ).each( function( i, tr ) {
465 $( tr ).find( 'td' ).each( function( i, td ) {
466 data.push( { data: $( td ).data( 'sort-value' ), text: $( td ).text() } );
508 tableTest( 'bug 8115: sort numbers with commas (ascending)',
509 ['Numbers'], numbers, numbersAsc,
511 $table.tablesorter();
512 $table.find( '.headerSort:eq(0)' ).click();
516 tableTest( 'bug 8115: sort numbers with commas (descending)',
517 ['Numbers'], numbers, reversed(numbersAsc),
519 $table.tablesorter();
520 $table.find( '.headerSort:eq(0)' ).click().click();
523 // TODO add numbers sorting tests for bug 8115 with a different language
525 test( 'bug 32888 - Tables inside a tableheader cell', function() {
530 '<table class="sortable" id="32888">' +
531 '<tr><th>header<table id="32888-2">'+
532 '<tr><th>1</th><th>2</th></tr>' +
533 '</table></th></tr>' +
534 '<tr><td>A</td></tr>' +
535 '<tr><td>B</td></tr>' +
538 $table.tablesorter();
541 $table.find('> thead:eq(0) > tr > th.headerSort').length,
543 'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
546 $('#32888-2').find('th.headerSort').length,
548 'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'