From: Matthew Flaschen Date: Wed, 6 Mar 2013 00:56:15 +0000 (-0800) Subject: Implement htmlEqual QUnit helper (QUnit.assert.htmlEqual) X-Git-Tag: 1.31.0-rc.0~20349^2 X-Git-Url: http://git.cyclocoop.org/%22.%20generer_url_ecrire%28%22sites_tous%22%2C%22%22%29.%20%22?a=commitdiff_plain;h=886ddf41f7ff504b315b1ad51d5eaf0d6f6417e4;p=lhc%2Fweb%2Fwiklou.git Implement htmlEqual QUnit helper (QUnit.assert.htmlEqual) Bug: 45526 Change-Id: I4d0ce6226f4ef73d659ba0635f2b2f49d8b0e9b5 --- diff --git a/RELEASE-NOTES-1.21 b/RELEASE-NOTES-1.21 index 58640699ac..f8c7aedee9 100644 --- a/RELEASE-NOTES-1.21 +++ b/RELEASE-NOTES-1.21 @@ -117,6 +117,9 @@ production. * Added 'HistoryRevisionTools' and 'DiffRevisionTools' hooks. * (bug 33186) Add image rotation api "imagerotate" * (bug 34040) Add "User rights management" link on user page toolbox. +* (bug 45526) Add QUnit assertion helper "QUnit.assert.htmlEqual" for asserting + structual equality of HTML (ignoring insignificant differences like + quotmarks, order and whitespace in the attribute list). === Bug fixes in 1.21 === * (bug 40353) SpecialDoubleRedirect should support interwiki redirects. diff --git a/resources/Resources.php b/resources/Resources.php index 10689cd15b..1a11cd4956 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -957,6 +957,7 @@ return array( 'mediawiki.tests.qunit.testrunner' => array( 'scripts' => 'tests/qunit/data/testrunner.js', 'dependencies' => array( + 'jquery.getAttrs', 'jquery.qunit', 'jquery.qunit.completenessTest', 'mediawiki.page.startup', diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js index 77db2131e4..62dd81ac28 100644 --- a/tests/qunit/data/testrunner.js +++ b/tests/qunit/data/testrunner.js @@ -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 @@ -179,6 +181,48 @@ 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 = $( '
' ).append( html )[0]; + return getDomStructure( el ); + } + /** * Add-on assertion helpers */ @@ -213,6 +257,50 @@ // 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 + ); } }; @@ -259,6 +347,56 @@ assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object restored and re-applied after test()' ); } ); + QUnit.test( 'htmlEqual', 8, function ( assert ) { + assert.htmlEqual( + '

Child paragraph with A link

Regular textA span
', + '

Child paragraph with A link

Regular textA span
', + 'Attribute order, spacing and quotation marks (equal)' + ); + + assert.notHtmlEqual( + '

Child paragraph with A link

Regular textA span
', + '

Child paragraph with A link

Regular textA span
', + 'Attribute order, spacing and quotation marks (not equal)' + ); + + assert.htmlEqual( + '', + '', + 'Multiple root nodes (equal)' + ); + + assert.notHtmlEqual( + '', + '', + 'Multiple root nodes (not equal, last label node is different)' + ); + + assert.htmlEqual( + 'fo"o
b>ar', + 'fo"o
b>ar', + 'Extra escaping is equal' + ); + assert.notHtmlEqual( + 'foo<br/>bar', + 'foo
bar', + 'Text escaping (not equal)' + ); + + assert.htmlEqual( + 'fooexamplebar', + 'fooexamplebar', + 'Outer text nodes are compared (equal)' + ); + + assert.notHtmlEqual( + 'fooexamplebar', + 'fooexamplequux', + 'Outer text nodes are compared (last text node different)' + ); + + } ); + QUnit.module( 'mediawiki.tests.qunit.testrunner-after', QUnit.newMwEnvironment() ); QUnit.test( 'Teardown', 3, function ( assert ) {