From 4cc2101ffd35171d0cde913062757858f9e8be86 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Thu, 25 Oct 2012 22:06:07 +0200 Subject: [PATCH] Test: Enforce # of expected assertions. Change-Id: I041c792d1841f69677f8c7d38f67108475a0afc9 --- modules/ve/test/ce/ve.ce.Document.test.js | 2 +- modules/ve/test/dm/ve.dm.Converter.test.js | 12 +- modules/ve/test/dm/ve.dm.Document.test.js | 5 +- modules/ve/test/dm/ve.dm.Transaction.test.js | 32 +- .../dm/ve.dm.TransactionProcessor.test.js | 422 +++++++++--------- modules/ve/test/ve.Range.test.js | 2 +- modules/ve/test/ve.qunit.js | 31 +- 7 files changed, 260 insertions(+), 246 deletions(-) diff --git a/modules/ve/test/ce/ve.ce.Document.test.js b/modules/ve/test/ce/ve.ce.Document.test.js index 756fcc8a52..8fafdae7a0 100644 --- a/modules/ve/test/ce/ve.ce.Document.test.js +++ b/modules/ve/test/ce/ve.ce.Document.test.js @@ -9,7 +9,7 @@ QUnit.module( 've.ce.Document' ); /* Tests */ -QUnit.test( 'selectNodes', function ( assert ) { +QUnit.test( 'selectNodes', 21, function ( assert ) { var i, len, doc = new ve.ce.Document( new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ) ), cases = ve.example.getSelectNodesCases( doc ); diff --git a/modules/ve/test/dm/ve.dm.Converter.test.js b/modules/ve/test/dm/ve.dm.Converter.test.js index 5367af2953..b11d19fd10 100644 --- a/modules/ve/test/dm/ve.dm.Converter.test.js +++ b/modules/ve/test/dm/ve.dm.Converter.test.js @@ -9,8 +9,9 @@ QUnit.module( 've.dm.Converter' ); /* Tests */ -QUnit.test( 'getDataElementFromDomElement', function ( assert ) { +QUnit.test( 'getDataElementFromDomElement', 20, function ( assert ) { var msg, conversion; + for ( msg in ve.dm.example.conversions ) { conversion = ve.dm.example.conversions[msg]; assert.deepEqual( @@ -21,8 +22,9 @@ QUnit.test( 'getDataElementFromDomElement', function ( assert ) { } } ); -QUnit.test( 'getDomElementFromDataElement', function ( assert ) { +QUnit.test( 'getDomElementFromDataElement', 20, function ( assert ) { var msg, conversion; + for ( msg in ve.dm.example.conversions ) { conversion = ve.dm.example.conversions[msg]; assert.equalDomElement( @@ -33,9 +35,10 @@ QUnit.test( 'getDomElementFromDataElement', function ( assert ) { } } ); -QUnit.test( 'getDataFromDom', function ( assert ) { +QUnit.test( 'getDataFromDom', 30, function ( assert ) { var msg, cases = ve.dm.example.domToDataCases; + for ( msg in cases ) { if ( cases[msg].html !== null ) { ve.dm.example.preprocessAnnotations( cases[msg].data ); @@ -48,9 +51,10 @@ QUnit.test( 'getDataFromDom', function ( assert ) { } } ); -QUnit.test( 'getDomFromData', function ( assert ) { +QUnit.test( 'getDomFromData', 31, function ( assert ) { var msg, cases = ve.dm.example.domToDataCases; + for ( msg in cases ) { ve.dm.example.preprocessAnnotations( cases[msg].data ); assert.equalDomElement( diff --git a/modules/ve/test/dm/ve.dm.Document.test.js b/modules/ve/test/dm/ve.dm.Document.test.js index aaa05d1a75..b3d9199798 100644 --- a/modules/ve/test/dm/ve.dm.Document.test.js +++ b/modules/ve/test/dm/ve.dm.Document.test.js @@ -845,7 +845,7 @@ QUnit.test( 'isContentData', 1, function ( assert ) { } } ); -QUnit.test( 'rebuildNodes', function ( assert ) { +QUnit.test( 'rebuildNodes', 2, function ( assert ) { var tree, doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), documentNode = doc.getDocumentNode(); @@ -1302,10 +1302,11 @@ QUnit.test( 'getNearestStructuralOffset', function ( assert ) { } } ); -QUnit.test( 'selectNodes', function ( assert ) { +QUnit.test( 'selectNodes', 21, function ( assert ) { var i, doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), cases = ve.example.getSelectNodesCases( doc ); + for ( i = 0; i < cases.length; i++ ) { assert.equalNodeSelection( cases[i].actual, cases[i].expected, cases[i].msg ); } diff --git a/modules/ve/test/dm/ve.dm.Transaction.test.js b/modules/ve/test/dm/ve.dm.Transaction.test.js index d6c41b8d79..7d404f90ba 100644 --- a/modules/ve/test/dm/ve.dm.Transaction.test.js +++ b/modules/ve/test/dm/ve.dm.Transaction.test.js @@ -42,10 +42,10 @@ function runConstructorTests( assert, constructor, cases ) { /* Tests */ -QUnit.test( 'newFromInsertion', function ( assert ) { - var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), +QUnit.test( 'newFromInsertion', 13, function ( assert ) { + var i, key, + doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), doc2 = new ve.dm.Document( [ { 'type': 'paragraph' }, { 'type': '/paragraph' } ] ), - i, key, cases = { 'paragraph before first element': { 'args': [doc, 0, [{ 'type': 'paragraph' }, '1', { 'type': '/paragraph' }]], @@ -219,10 +219,10 @@ QUnit.test( 'newFromInsertion', function ( assert ) { runConstructorTests( assert, ve.dm.Transaction.newFromInsertion, cases ); } ); -QUnit.test( 'newFromRemoval', function ( assert ) { - var alienDoc = new ve.dm.Document( ve.copyArray( ve.dm.example.alienData ) ), +QUnit.test( 'newFromRemoval', 15, function ( assert ) { + var i, key, + alienDoc = new ve.dm.Document( ve.copyArray( ve.dm.example.alienData ) ), doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), - i, key, cases = { 'content in first element': { 'args': [doc, new ve.Range( 1, 3 )], @@ -463,7 +463,7 @@ QUnit.test( 'newFromRemoval', function ( assert ) { runConstructorTests( assert, ve.dm.Transaction.newFromRemoval, cases ); } ); -QUnit.test( 'newFromAttributeChange', function ( assert ) { +QUnit.test( 'newFromAttributeChange', 4, function ( assert ) { var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), cases = { 'first element': { @@ -503,7 +503,7 @@ QUnit.test( 'newFromAttributeChange', function ( assert ) { runConstructorTests( assert, ve.dm.Transaction.newFromAttributeChange, cases ); } ); -QUnit.test( 'newFromAnnotation', function ( assert ) { +QUnit.test( 'newFromAnnotation', 4, function ( assert ) { var bold = ve.dm.example.createAnnotation( ve.dm.example.bold ), doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), cases = { @@ -605,7 +605,7 @@ QUnit.test( 'newFromAnnotation', function ( assert ) { runConstructorTests( assert, ve.dm.Transaction.newFromAnnotation, cases ); } ); -QUnit.test( 'newFromContentBranchConversion', function ( assert ) { +QUnit.test( 'newFromContentBranchConversion', 2, function ( assert ) { var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), i, key, cases = { @@ -674,9 +674,9 @@ QUnit.test( 'newFromContentBranchConversion', function ( assert ) { ); } ); -QUnit.test( 'newFromWrap', function ( assert ) { - var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), - i, key, +QUnit.test( 'newFromWrap', 8, function ( assert ) { + var i, key, + doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ), cases = { 'changes a heading to a paragraph': { 'args': [doc, new ve.Range( 1, 4 ), [ { 'type': 'heading', 'attributes': { 'level': 1 } } ], [ { 'type': 'paragraph' } ], [], []], @@ -845,7 +845,7 @@ QUnit.test( 'translateOffsetReversed', function ( assert ) { } } ); -QUnit.test( 'pushRetain', function ( assert ) { +QUnit.test( 'pushRetain', 4, function ( assert ) { var cases = { 'retain': { 'calls': [['pushRetain', 5]], @@ -861,7 +861,7 @@ QUnit.test( 'pushRetain', function ( assert ) { runBuilderTests( assert, cases ); } ); -QUnit.test( 'pushReplace', function ( assert ) { +QUnit.test( 'pushReplace', 16, function ( assert ) { var i, key, cases = { 'insert': { 'calls': [ @@ -1001,7 +1001,7 @@ QUnit.test( 'pushReplace', function ( assert ) { runBuilderTests( assert, cases ); } ); -QUnit.test( 'pushReplaceElementAttribute', function ( assert ) { +QUnit.test( 'pushReplaceElementAttribute', 4, function ( assert ) { var cases = { 'replace element attribute': { 'calls': [ @@ -1042,7 +1042,7 @@ QUnit.test( 'pushReplaceElementAttribute', function ( assert ) { runBuilderTests( assert, cases ); } ); -QUnit.test( 'push*Annotating', function ( assert ) { +QUnit.test( 'push*Annotating', 8, function ( assert ) { var cases = { 'start annotating': { 'calls': [ diff --git a/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js b/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js index 598f4ce083..59301749a8 100644 --- a/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js +++ b/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js @@ -40,223 +40,225 @@ QUnit.test( 'protection against double application', 3, function ( assert ) { ); } ); -QUnit.test( 'commit/rollback', function ( assert ) { - var i, key, originalData, originalDoc, msg, testDocument, tx, expectedData, expectedDocument, +QUnit.test( 'commit/rollback', 58, function ( assert ) { + var i, key, originalData, originalDoc, msg, testDocument, tx, + expectedData, expectedDocument, bold = ve.dm.example.createAnnotation( ve.dm.example.bold ), italic = ve.dm.example.createAnnotation( ve.dm.example.italic ), underline = ve.dm.example.createAnnotation( ve.dm.example.underline ), cases = { - 'no operations': { - 'calls': [], - 'expected': function () {} - }, - 'retaining': { - 'calls': [['pushRetain', 38]], - 'expected': function () {} - }, - 'annotating content': { - 'calls': [ - ['pushRetain', 1], - ['pushStartAnnotating', 'set', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'set', bold], - ['pushRetain', 1], - ['pushStartAnnotating', 'clear', italic], - ['pushStartAnnotating', 'set', bold], - ['pushStartAnnotating', 'set', underline], - ['pushRetain', 1], - ['pushStopAnnotating', 'clear', italic], - ['pushStopAnnotating', 'set', bold], - ['pushStopAnnotating', 'set', underline] - ], - 'expected': function ( data ) { - data[1] = ['a', new ve.AnnotationSet( [ bold ] )]; - data[2] = ['b', new ve.AnnotationSet( [ bold ] )]; - data[3] = ['c', new ve.AnnotationSet( [ bold, underline ] )]; - } - }, - 'annotating content and leaf elements': { - 'calls': [ - ['pushRetain', 38], - ['pushStartAnnotating', 'set', bold], - ['pushRetain', 2], - ['pushStopAnnotating', 'set', bold] - ], - 'expected': function ( data ) { - data[38] = ['h', new ve.AnnotationSet( [ bold ] )]; - data[39].annotations = new ve.AnnotationSet( [ bold ] ); - } - }, - 'using an annotation method other than set or clear throws an exception': { - 'calls': [ - ['pushStartAnnotating', 'invalid-method', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'invalid-method', bold] - ], - 'exception': Error - }, - 'annotating branch opening element throws an exception': { - 'calls': [ - ['pushStartAnnotating', 'set', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'set', bold] - ], - 'exception': Error - }, - 'annotating branch closing element throws an exception': { - 'calls': [ - ['pushRetain', 4], - ['pushStartAnnotating', 'set', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'set', bold] - ], - 'exception': Error - }, - 'setting duplicate annotations throws an exception': { - 'calls': [ - ['pushRetain', 2], - ['pushStartAnnotating', 'set', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'set', bold] - ], - 'exception': Error - }, - 'removing non-existent annotations throws an exception': { - 'calls': [ - ['pushRetain', 1], - ['pushStartAnnotating', 'clear', bold], - ['pushRetain', 1], - ['pushStopAnnotating', 'clear', bold] - ], - 'exception': Error - }, - 'changing, removing and adding attributes': { - 'calls': [ - ['pushReplaceElementAttribute', 'level', 1, 2], - ['pushRetain', 12], - ['pushReplaceElementAttribute', 'style', 'bullet', 'number'], - ['pushReplaceElementAttribute', 'test', undefined, 'abcd'], - ['pushRetain', 27], - ['pushReplaceElementAttribute', 'html/src', 'image.png', undefined] - ], - 'expected': function ( data ) { - data[0].attributes.level = 2; - data[12].attributes.style = 'number'; - data[12].attributes.test = 'abcd'; - delete data[39].attributes['html/src']; - } - }, - 'changing attributes on non-element data throws an exception': { - 'calls': [ - ['pushRetain', 1], - ['pushReplaceElementAttribute', 'foo', 23, 42] - ], - 'exception': Error - }, - 'inserting text': { - 'calls': [ - ['pushRetain', 1], - ['pushReplace', [], ['F', 'O', 'O']] - ], - 'expected': function ( data ) { - data.splice( 1, 0, 'F', 'O', 'O' ); - } - }, - 'removing text': { - 'calls': [ - ['pushRetain', 1], - ['pushReplace', ['a'], []] - ], - 'expected': function ( data ) { - data.splice( 1, 1 ); - } - }, - 'replacing text': { - 'calls': [ - ['pushRetain', 1], - ['pushReplace', ['a'], ['F', 'O', 'O']] - ], - 'expected': function ( data ) { - data.splice( 1, 1, 'F', 'O', 'O' ); - } - }, - 'inserting mixed content': { - 'calls': [ - ['pushRetain', 1], - ['pushReplace', ['a'], ['F', 'O', 'O', {'type':'image'}, {'type':'/image'}, 'B', 'A', 'R']] - ], - 'expected': function ( data ) { - data.splice( 1, 1, 'F', 'O', 'O', {'type':'image'}, {'type':'/image'}, 'B', 'A', 'R' ); - } - }, - 'converting an element': { - 'calls': [ - [ - 'pushReplace', - [{ 'type': 'heading', 'attributes': { 'level': 1 } }], - [{ 'type': 'paragraph' }] + 'no operations': { + 'calls': [], + 'expected': function () {} + }, + 'retaining': { + 'calls': [['pushRetain', 38]], + 'expected': function () {} + }, + 'annotating content': { + 'calls': [ + ['pushRetain', 1], + ['pushStartAnnotating', 'set', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'set', bold], + ['pushRetain', 1], + ['pushStartAnnotating', 'clear', italic], + ['pushStartAnnotating', 'set', bold], + ['pushStartAnnotating', 'set', underline], + ['pushRetain', 1], + ['pushStopAnnotating', 'clear', italic], + ['pushStopAnnotating', 'set', bold], + ['pushStopAnnotating', 'set', underline] ], - ['pushRetain', 3], - ['pushReplace', [{ 'type': '/heading' }], [{ 'type': '/paragraph' }]] - ], - 'expected': function ( data ) { - data[0].type = 'paragraph'; - delete data[0].attributes; - data[4].type = '/paragraph'; - } - }, - 'splitting an element': { - 'calls': [ - ['pushRetain', 2], - [ - 'pushReplace', - [], - [{ 'type': '/heading' }, { 'type': 'heading', 'attributes': { 'level': 1 } }] - ] - ], - 'expected': function ( data ) { - data.splice( - 2, - 0, - { 'type': '/heading' }, - { 'type': 'heading', 'attributes': { 'level': 1 } } - ); - } - }, - 'merging an element': { - 'calls': [ - ['pushRetain', 57], - [ - 'pushReplace', - [{ 'type': '/paragraph' }, { 'type': 'paragraph' }], - [] - ] - ], - 'expected': function ( data ) { - data.splice( 57, 2 ); - } - }, - 'stripping elements': { - 'calls': [ - ['pushRetain', 3], - [ - 'pushReplace', - [['c', [ ve.dm.example.italic ]]], - [] + 'expected': function ( data ) { + data[1] = ['a', new ve.AnnotationSet( [ bold ] )]; + data[2] = ['b', new ve.AnnotationSet( [ bold ] )]; + data[3] = ['c', new ve.AnnotationSet( [ bold, underline ] )]; + } + }, + 'annotating content and leaf elements': { + 'calls': [ + ['pushRetain', 38], + ['pushStartAnnotating', 'set', bold], + ['pushRetain', 2], + ['pushStopAnnotating', 'set', bold] ], - ['pushRetain', 6], - [ - 'pushReplace', - ['d'], - [] - ] - ], - 'expected': function ( data ) { - data.splice( 10, 1 ); - data.splice( 3, 1 ); + 'expected': function ( data ) { + data[38] = ['h', new ve.AnnotationSet( [ bold ] )]; + data[39].annotations = new ve.AnnotationSet( [ bold ] ); + } + }, + 'using an annotation method other than set or clear throws an exception': { + 'calls': [ + ['pushStartAnnotating', 'invalid-method', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'invalid-method', bold] + ], + 'exception': Error + }, + 'annotating branch opening element throws an exception': { + 'calls': [ + ['pushStartAnnotating', 'set', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'set', bold] + ], + 'exception': Error + }, + 'annotating branch closing element throws an exception': { + 'calls': [ + ['pushRetain', 4], + ['pushStartAnnotating', 'set', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'set', bold] + ], + 'exception': Error + }, + 'setting duplicate annotations throws an exception': { + 'calls': [ + ['pushRetain', 2], + ['pushStartAnnotating', 'set', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'set', bold] + ], + 'exception': Error + }, + 'removing non-existent annotations throws an exception': { + 'calls': [ + ['pushRetain', 1], + ['pushStartAnnotating', 'clear', bold], + ['pushRetain', 1], + ['pushStopAnnotating', 'clear', bold] + ], + 'exception': Error + }, + 'changing, removing and adding attributes': { + 'calls': [ + ['pushReplaceElementAttribute', 'level', 1, 2], + ['pushRetain', 12], + ['pushReplaceElementAttribute', 'style', 'bullet', 'number'], + ['pushReplaceElementAttribute', 'test', undefined, 'abcd'], + ['pushRetain', 27], + ['pushReplaceElementAttribute', 'html/src', 'image.png', undefined] + ], + 'expected': function ( data ) { + data[0].attributes.level = 2; + data[12].attributes.style = 'number'; + data[12].attributes.test = 'abcd'; + delete data[39].attributes['html/src']; + } + }, + 'changing attributes on non-element data throws an exception': { + 'calls': [ + ['pushRetain', 1], + ['pushReplaceElementAttribute', 'foo', 23, 42] + ], + 'exception': Error + }, + 'inserting text': { + 'calls': [ + ['pushRetain', 1], + ['pushReplace', [], ['F', 'O', 'O']] + ], + 'expected': function ( data ) { + data.splice( 1, 0, 'F', 'O', 'O' ); + } + }, + 'removing text': { + 'calls': [ + ['pushRetain', 1], + ['pushReplace', ['a'], []] + ], + 'expected': function ( data ) { + data.splice( 1, 1 ); + } + }, + 'replacing text': { + 'calls': [ + ['pushRetain', 1], + ['pushReplace', ['a'], ['F', 'O', 'O']] + ], + 'expected': function ( data ) { + data.splice( 1, 1, 'F', 'O', 'O' ); + } + }, + 'inserting mixed content': { + 'calls': [ + ['pushRetain', 1], + ['pushReplace', ['a'], ['F', 'O', 'O', {'type':'image'}, {'type':'/image'}, 'B', 'A', 'R']] + ], + 'expected': function ( data ) { + data.splice( 1, 1, 'F', 'O', 'O', {'type':'image'}, {'type':'/image'}, 'B', 'A', 'R' ); + } + }, + 'converting an element': { + 'calls': [ + [ + 'pushReplace', + [{ 'type': 'heading', 'attributes': { 'level': 1 } }], + [{ 'type': 'paragraph' }] + ], + ['pushRetain', 3], + ['pushReplace', [{ 'type': '/heading' }], [{ 'type': '/paragraph' }]] + ], + 'expected': function ( data ) { + data[0].type = 'paragraph'; + delete data[0].attributes; + data[4].type = '/paragraph'; + } + }, + 'splitting an element': { + 'calls': [ + ['pushRetain', 2], + [ + 'pushReplace', + [], + [{ 'type': '/heading' }, { 'type': 'heading', 'attributes': { 'level': 1 } }] + ] + ], + 'expected': function ( data ) { + data.splice( + 2, + 0, + { 'type': '/heading' }, + { 'type': 'heading', 'attributes': { 'level': 1 } } + ); + } + }, + 'merging an element': { + 'calls': [ + ['pushRetain', 57], + [ + 'pushReplace', + [{ 'type': '/paragraph' }, { 'type': 'paragraph' }], + [] + ] + ], + 'expected': function ( data ) { + data.splice( 57, 2 ); + } + }, + 'stripping elements': { + 'calls': [ + ['pushRetain', 3], + [ + 'pushReplace', + [['c', [ ve.dm.example.italic ]]], + [] + ], + ['pushRetain', 6], + [ + 'pushReplace', + ['d'], + [] + ] + ], + 'expected': function ( data ) { + data.splice( 10, 1 ); + data.splice( 3, 1 ); + } } - } - }; + }; + for ( key in cases ) { for ( i = 0; i < cases[key].calls.length; i++ ) { if ( cases[key].calls[i][0] === 'pushReplace' ) { diff --git a/modules/ve/test/ve.Range.test.js b/modules/ve/test/ve.Range.test.js index 56716456d3..3a81a3c4a6 100644 --- a/modules/ve/test/ve.Range.test.js +++ b/modules/ve/test/ve.Range.test.js @@ -9,7 +9,7 @@ QUnit.module( 've.Range' ); /* Tests */ -QUnit.test( 'Basic usage', function ( assert ) { +QUnit.test( 'Basic usage', 8, function ( assert ) { var range; range = new ve.Range( 100 , 200 ); diff --git a/modules/ve/test/ve.qunit.js b/modules/ve/test/ve.qunit.js index 598c77e507..f418dc99b3 100644 --- a/modules/ve/test/ve.qunit.js +++ b/modules/ve/test/ve.qunit.js @@ -1,5 +1,7 @@ ( function ( QUnit ) { +QUnit.config.requireExpects = true; + /** * Builds a summary of a node tree. * @@ -14,11 +16,12 @@ function getNodeTreeSummary( node, shallow ) { var i, summary = { - 'getType': node.getType(), - 'getLength': node.getLength(), - 'getOuterLength': node.getOuterLength(), - 'attributes': node.attributes - }; + 'getType': node.getType(), + 'getLength': node.getLength(), + 'getOuterLength': node.getOuterLength(), + 'attributes': node.attributes + }; + if ( node.children !== undefined ) { summary['children.length'] = node.children.length; if ( !shallow ) { @@ -44,8 +47,9 @@ function getNodeTreeSummary( node, shallow ) { function getNodeSelectionSummary( selection ) { var i, summary = { - 'length': selection.length - }; + 'length': selection.length + }; + if ( selection.length ) { summary.results = []; for ( i = 0; i < selection.length; i++ ) { @@ -69,18 +73,19 @@ function getNodeSelectionSummary( selection ) { * Summaries include node name, text, attributes and recursive summaries of children. * * @method - * @param {HTMLElement} element Element to summarize - * @returns {Object} Summary of element + * @param {HTMLElement} element Element to summarize. + * @returns {Object} Summary of element. */ function getDomElementSummary( element ) { - var $element = $( element ), + var i, + $element = $( element ), summary = { 'type': element.nodeName.toLowerCase(), 'text': $element.text(), 'attributes': {}, 'children': [] - }, - i; + }; + // Gather attributes for ( i = 0; i < element.attributes.length; i++ ) { summary.attributes[element.attributes[i].name] = element.attributes[i].value; @@ -108,6 +113,7 @@ QUnit.assert.equalNodeSelection = function ( actual, expected, message ) { var i, actualSummary = getNodeSelectionSummary( actual ), expectedSummary = getNodeSelectionSummary( expected ); + for ( i = 0; i < actual.length; i++ ) { if ( expected[i] && expected[i].node !== actual[i].node ) { QUnit.push( false, actualSummary, expectedSummary, @@ -124,6 +130,7 @@ QUnit.assert.equalNodeSelection = function ( actual, expected, message ) { QUnit.assert.equalDomElement = function ( actual, expected, message ) { var actualSummary = getDomElementSummary( actual ), expectedSummary = getDomElementSummary( expected ); + QUnit.push( QUnit.equiv( actualSummary, expectedSummary ), actualSummary, expectedSummary, message );