Merge "QUnit: Re-enable config.requireExpects and add missing numbers."
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 25 Mar 2013 14:59:12 +0000 (14:59 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 25 Mar 2013 14:59:12 +0000 (14:59 +0000)
1  2 
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js

@@@ -5,9 -5,7 +5,9 @@@
  
        var mwTestIgnore, mwTester,
                addons,
 -              envExecCount;
 +              envExecCount,
 +              ELEMENT_NODE = 1,
 +              TEXT_NODE = 3;
  
        /**
         * Add bogus to url to prevent IE crazy caching
@@@ -38,6 -36,8 +38,8 @@@
                tooltip: 'Enable debug mode in ResourceLoader'
        } );
  
+       QUnit.config.requireExpects = true;
        /**
         * Load TestSwarm agent
         */
@@@ -54,7 -54,7 +56,7 @@@
        /**
         * CompletenessTest
         */
-        // Adds toggle checkbox to header
+       // Adds toggle checkbox to header
        QUnit.config.urlConfig.push( {
                id: 'completenesstest',
                label: 'Run CompletenessTest',
                return $.when.apply( $, altPromises );
        };
  
 +      /**
 +       * Recursively convert a node to a plain object representing its structure.
 +       * Only considers attributes and contents (elements and text nodes).
 +       * Attribute values are compared strictly and not normalised.
 +       *
 +       * @param {Node} node
 +       * @return {Object|string} Plain JavaScript value representing the node.
 +       */
 +      function getDomStructure( node ) {
 +              var $node, children, processedChildren, i, len, el;
 +              $node = $( node );
 +              if ( node.nodeType === ELEMENT_NODE ) {
 +                      children = $node.contents();
 +                      processedChildren = [];
 +                      for ( i = 0, len = children.length; i < len; i++ ) {
 +                              el = children[i];
 +                              if ( el.nodeType === ELEMENT_NODE || el.nodeType === TEXT_NODE ) {
 +                                      processedChildren.push( getDomStructure( el ) );
 +                              }
 +                      }
 +
 +                      return {
 +                              tagName: node.tagName,
 +                              attributes: $node.getAttrs(),
 +                              contents: processedChildren
 +                      };
 +              } else {
 +                      // Should be text node
 +                      return $node.text();
 +              }
 +      }
 +
 +      /**
 +       * Gets structure of node for this HTML.
 +       *
 +       * @param {string} html HTML markup for one or more nodes.
 +       */
 +      function getHtmlStructure( html ) {
 +              var el = $( '<div>' ).append( html )[0];
 +              return getDomStructure( el );
 +      }
 +
        /**
         * Add-on assertion helpers
         */
                // Expect numerical value greater than or equal to X
                gtOrEq: function ( actual, expected, message ) {
                        QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
 +              },
 +
 +              /**
 +               * Asserts that two HTML strings are structurally equivalent.
 +               *
 +               * @param {string} actualHtml Actual HTML markup.
 +               * @param {string} expectedHtml Expected HTML markup
 +               * @param {string} message Assertion message.
 +               */
 +              htmlEqual: function ( actualHtml, expectedHtml, message ) {
 +                      var actual = getHtmlStructure( actualHtml ),
 +                              expected = getHtmlStructure( expectedHtml );
 +
 +                      QUnit.push(
 +                              QUnit.equiv(
 +                                      actual,
 +                                      expected
 +                              ),
 +                              actual,
 +                              expected,
 +                              message
 +                      );
 +              },
 +
 +              /**
 +               * Asserts that two HTML strings are not structurally equivalent.
 +               *
 +               * @param {string} actualHtml Actual HTML markup.
 +               * @param {string} expectedHtml Expected HTML markup.
 +               * @param {string} message Assertion message.
 +               */
 +              notHtmlEqual: function ( actualHtml, expectedHtml, message ) {
 +                      var actual = getHtmlStructure( actualHtml ),
 +                              expected = getHtmlStructure( expectedHtml );
 +
 +                      QUnit.push(
 +                              !QUnit.equiv(
 +                                      actual,
 +                                      expected
 +                              ),
 +                              actual,
 +                              expected,
 +                              message
 +                      );
                }
        };
  
                assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object restored and re-applied after test()' );
        } );
  
 +      QUnit.test( 'htmlEqual', 8, function ( assert ) {
 +              assert.htmlEqual(
 +                      '<div><p class="some classes" data-length="10">Child paragraph with <a href="http://example.com">A link</a></p>Regular text<span>A span</span></div>',
 +                      '<div><p data-length=\'10\'  class=\'some classes\'>Child paragraph with <a href=\'http://example.com\' >A link</a></p>Regular text<span>A span</span></div>',
 +                      'Attribute order, spacing and quotation marks (equal)'
 +              );
 +
 +              assert.notHtmlEqual(
 +                      '<div><p class="some classes" data-length="10">Child paragraph with <a href="http://example.com">A link</a></p>Regular text<span>A span</span></div>',
 +                      '<div><p data-length=\'10\'  class=\'some more classes\'>Child paragraph with <a href=\'http://example.com\' >A link</a></p>Regular text<span>A span</span></div>',
 +                      'Attribute order, spacing and quotation marks (not equal)'
 +              );
 +
 +              assert.htmlEqual(
 +                      '<label for="firstname" accesskey="f" class="important">First</label><input id="firstname" /><label for="lastname" accesskey="l" class="minor">Last</label><input id="lastname" />',
 +                      '<label for="firstname" accesskey="f" class="important">First</label><input id="firstname" /><label for="lastname" accesskey="l" class="minor">Last</label><input id="lastname" />',
 +                      'Multiple root nodes (equal)'
 +              );
 +
 +              assert.notHtmlEqual(
 +                      '<label for="firstname" accesskey="f" class="important">First</label><input id="firstname" /><label for="lastname" accesskey="l" class="minor">Last</label><input id="lastname" />',
 +                      '<label for="firstname" accesskey="f" class="important">First</label><input id="firstname" /><label for="lastname" accesskey="l" class="important" >Last</label><input id="lastname" />',
 +                      'Multiple root nodes (not equal, last label node is different)'
 +              );
 +
 +              assert.htmlEqual(
 +                      'fo&quot;o<br/>b&gt;ar',
 +                      'fo"o<br/>b>ar',
 +                      'Extra escaping is equal'
 +              );
 +              assert.notHtmlEqual(
 +                      'foo&lt;br/&gt;bar',
 +                      'foo<br/>bar',
 +                      'Text escaping (not equal)'
 +              );
 +
 +              assert.htmlEqual(
 +                      'foo<a href="http://example.com">example</a>bar',
 +                      'foo<a href="http://example.com">example</a>bar',
 +                      'Outer text nodes are compared (equal)'
 +              );
 +
 +              assert.notHtmlEqual(
 +                      'foo<a href="http://example.com">example</a>bar',
 +                      'foo<a href="http://example.com">example</a>quux',
 +                      'Outer text nodes are compared (last text node different)'
 +              );
 +
 +      } );
 +
        QUnit.module( 'mediawiki.tests.qunit.testrunner-after', QUnit.newMwEnvironment() );
  
        QUnit.test( 'Teardown', 3, function ( assert ) {
                } );
        }
  
 +      /**
 +       * Run a table test by building a table with the given HTML,
 +       * running some callback on it, then checking the results.
 +       *
 +       * @param {String} msg text to pass on to qunit for the comparison
 +       * @param {String} HTML to make the table
 +       * @param {String[][]} expected rows/cols to compare against at end
 +       * @param {function($table)} callback something to do with the table before we compare
 +       */
 +      function tableTestHTML( msg, html, expected, callback ) {
 +              QUnit.test( msg, 1, function ( assert ) {
 +                      var $table = $( html );
 +
 +                      // Give caller a chance to set up sorting and manipulate the table.
 +                      if ( callback ) {
 +                              callback( $table );
 +                      } else {
 +                              $table.tablesorter();
 +                              $table.find( '#sortme' ).click();
 +                      }
 +
 +                      // Table sorting is done synchronously; if it ever needs to change back
 +                      // to asynchronous, we'll need a timeout or a callback here.
 +                      var extracted = tableExtract( $table );
 +                      assert.deepEqual( extracted, expected, msg );
 +              } );
 +      }
 +
        function reversed( arr ) {
                // Clone array
                var arr2 = arr.slice( 0 );
                }
        );
  
-       QUnit.test( 'Test detection routine', function ( assert ) {
+       QUnit.test( 'Test detection routine', 1, function ( assert ) {
                var $table;
                $table = $(
                        '<table class="sortable">' +
        } );
  
        /** FIXME: the diff output is not very readeable. */
-       QUnit.test( 'bug 32047 - caption must be before thead', function ( assert ) {
+       QUnit.test( 'bug 32047 - caption must be before thead', 1, function ( assert ) {
                var $table;
                $table = $(
                        '<table class="sortable">' +
                );
        } );
  
-       QUnit.test( 'data-sort-value attribute, when available, should override sorting position', function ( assert ) {
+       QUnit.test( 'data-sort-value attribute, when available, should override sorting position', 3, function ( assert ) {
                var $table, data;
  
                // Example 1: All cells except one cell without data-sort-value,
                }
        );
  
-       QUnit.test( 'Sorting images using alt text', function ( assert ) {
+       QUnit.test( 'Sorting images using alt text', 1, function ( assert ) {
                var $table = $(
                        '<table class="sortable">' +
                                '<tr><th>THEAD</th></tr>' +
                );
        } );
  
-       QUnit.test( 'Sorting images using alt text (complex)', function ( assert ) {
+       QUnit.test( 'Sorting images using alt text (complex)', 1, function ( assert ) {
                var $table = $(
                        '<table class="sortable">' +
                                '<tr><th>THEAD</th></tr>' +
                );
        } );
  
-       QUnit.test( 'Sorting images using alt text (with format autodetection)', function ( assert ) {
+       QUnit.test( 'Sorting images using alt text (with format autodetection)', 1, function ( assert ) {
                var $table = $(
                        '<table class="sortable">' +
                                '<tr><th>THEAD</th></tr>' +
                        'Applied correct sorting order'
                );
        } );
 +
 +      // bug 41889 - exploding rowspans in more complex cases
 +      tableTestHTML(
 +              'Rowspan exploding with row headers',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><th rowspan="2">foo</th><td rowspan="2">bar</td><td>baz</td></tr>' +
 +                      '<tr><td>2</td><td>baz</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo', 'bar', 'baz' ],
 +                      [ '2', 'foo', 'bar', 'baz' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with colspanned cells',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td></tr>' +
 +                      '<tr><td>2</td><td colspan="2">foobar</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo', 'bar', 'baz' ],
 +                      [ '2', 'foobar', 'baz' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with colspanned cells (2)',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th><th>quux</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td><td>quux</td></tr>' +
 +                      '<tr><td>2</td><td colspan="2">foobar</td><td>quux</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo', 'bar', 'baz', 'quux' ],
 +                      [ '2', 'foobar', 'baz', 'quux' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with rightmost rows spanning most',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td></tr>' +
 +                      '<tr><td>2</td></tr>' +
 +                      '<tr><td>3</td><td rowspan="2">foo</td></tr>' +
 +                      '<tr><td>4</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo', 'bar' ],
 +                      [ '2', 'foo', 'bar' ],
 +                      [ '3', 'foo', 'bar' ],
 +                      [ '4', 'foo', 'bar' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with rightmost rows spanning most (2)',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td><td>baz</td></tr>' +
 +                      '<tr><td>2</td><td>baz</td></tr>' +
 +                      '<tr><td>3</td><td rowspan="2">foo</td><td>baz</td></tr>' +
 +                      '<tr><td>4</td><td>baz</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo', 'bar', 'baz' ],
 +                      [ '2', 'foo', 'bar', 'baz' ],
 +                      [ '3', 'foo', 'bar', 'baz' ],
 +                      [ '4', 'foo', 'bar', 'baz' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with row-and-colspanned cells',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>bar</th><th>baz</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="4">bar</td><td>baz</td></tr>' +
 +                      '<tr><td>2</td><td>baz</td></tr>' +
 +                      '<tr><td>3</td><td colspan="2" rowspan="2">foo</td><td>baz</td></tr>' +
 +                      '<tr><td>4</td><td>baz</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo1', 'foo2', 'bar', 'baz' ],
 +                      [ '2', 'foo1', 'foo2', 'bar', 'baz' ],
 +                      [ '3', 'foo', 'bar', 'baz' ],
 +                      [ '4', 'foo', 'bar', 'baz' ]
 +              ]
 +      );
 +
 +      tableTestHTML(
 +              'Rowspan exploding with uneven rowspan layout',
 +              '<table class="sortable">' +
 +                      '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>foo3</th><th>bar</th><th>baz</th></tr></thead>' +
 +                      '<tbody>' +
 +                      '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>bar</td><td>baz</td></tr>' +
 +                      '<tr><td>2</td><td rowspan="3">bar</td><td>baz</td></tr>' +
 +                      '<tr><td>3</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>baz</td></tr>' +
 +                      '<tr><td>4</td><td>baz</td></tr>' +
 +                      '</tbody></table>',
 +              [
 +                      [ '1', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
 +                      [ '2', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
 +                      [ '3', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
 +                      [ '4', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ]
 +              ]
 +      );
 +
  }( jQuery, mediaWiki ) );