jenkins-bot has submitted this change and it was merged. Change subject: Tests for getNodeAndOffset (matching current quirky behaviour) ......................................................................
Tests for getNodeAndOffset (matching current quirky behaviour) Bug: T96838 Change-Id: I8a211a19bd798e920c0800c9e8d7bd53cf5d49dd --- M tests/ce/ve.ce.Document.test.js M tests/ve.test.utils.js 2 files changed, 166 insertions(+), 1 deletion(-) Approvals: Jforrester: Looks good to me, approved jenkins-bot: Verified diff --git a/tests/ce/ve.ce.Document.test.js b/tests/ce/ve.ce.Document.test.js index bec5689..0ccddec 100644 --- a/tests/ce/ve.ce.Document.test.js +++ b/tests/ce/ve.ce.Document.test.js @@ -10,5 +10,106 @@ // TODO: getNodeFromOffset // TODO: getSlugAtOffset -// TODO: getNodeAndOffset // TODO: getDirectionFromSelection + +QUnit.test( 'getNodeAndOffset', function ( assert ) { + var tests, i, len, test, parts, surface, data, ceDoc, rootNode, offsetCount, offset, position; + + // Each test below has the following: + // html: an input document + // data: the expected DM content + // positions: the node+offset corresponding to each DM offset, shown by marking pipe + // characters on a modified HTML representation in which text nodes are wrapped in + // <#text>...</#text> tags (and most attributes are omitted) + // dies (optional): a list of DM offsets where getNodeAndOffset is expected to die + /*jscs:disable validateQuoteMarks */ + tests = [ + { + title: 'Simple para', + html: '<p>x</p>', + data: [ '<paragraph>', 'x', '</paragraph>' ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-paragraphNode'><#text>||x|</#text></p></div>" + }, + { + title: 'Bold', + html: '<p>x<b>y</b>z</p>', + data: [ '<paragraph>', 'x', 'y', 'z', '</paragraph>' ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-paragraphNode'><#text>||x|</#text><b class='ve-ce-textStyleAnnotation ve-ce-boldAnnotation'><#text>y|</#text></b><#text>z|</#text></p></div>" + }, + { + title: 'Nested block nodes', + html: '<div><p>x</p></div>', + data: [ '<div>', '<paragraph>', 'x', '</paragraph>', '</div>' ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><div class='ve-ce-branchNode-slug ve-ce-branchNode-blockSlug'>|</div><div class='ve-ce-branchNode'><p class='ve-ce-branchNode ve-ce-paragraphNode'><#text>||x|</#text></p></div><div class='ve-ce-branchNode-slug ve-ce-branchNode-blockSlug'></div>|</div>", + dies: [ 4 ] + } + ]; + /*jscs:enable validateQuoteMarks */ + + QUnit.expect( tests.reduce( function ( total, test ) { + return total + test.positions.replace( /[^|]/g, '' ).length + 2; + }, 0 ) ); + + function showModelItem( item ) { + if ( item.type ) { + return '<' + item.type + '>'; + } else if ( Array.isArray( item ) ) { + return item[0]; + } else if ( typeof item === 'string' ) { + return item; + } else { + return '(unexpected: ' + item + ')'; + } + } + + for ( i = 0, len = tests.length; i < len; i++ ) { + test = tests[i]; + parts = test.positions.split( /[|]/ ); + surface = ve.test.utils.createSurfaceFromHtml( test.html ); + data = surface.getModel().getDocument().data.data + .slice( 0, -2 ) + .map( showModelItem ); + ceDoc = surface.getView().documentView; + rootNode = ceDoc.getDocumentNode().$element.get( 0 ); + + assert.deepEqual( data, test.data, test.title + ' (data)' ); + + offsetCount = data.length; + assert.strictEqual( + offsetCount, + test.positions.replace( /[^|]/g, '' ).length, + test.title + ' (offset count)' + ); + + for ( offset = 0; offset < offsetCount; offset++ ) { + try { + position = ceDoc.getNodeAndOffset( offset ); + if ( test.dies && test.dies.indexOf( offset ) !== -1 ) { + assert.ok( false, test.title + ' (' + offset + ') does not die' ); + continue; + } + } catch ( ex ) { + assert.ok( + test.dies && test.dies.indexOf( offset ) !== -1, + test.title + ' (' + offset + ') dies' + ); + continue; + } + + position = ceDoc.getNodeAndOffset( offset ); + assert.strictEqual( + ve.test.utils.serializePosition( + rootNode, + ceDoc.getNodeAndOffset( offset ), + { ignore: '.ve-ce-branchNode-blockSlug>*' } + ), + [].concat( + parts.slice( 0, offset + 1 ), + ['|'], + parts.slice( offset + 1 ) + ).join( '' ), + test.title + ' (' + offset + ')' + ); + } + } +} ); diff --git a/tests/ve.test.utils.js b/tests/ve.test.utils.js index 4639149..9428548 100644 --- a/tests/ve.test.utils.js +++ b/tests/ve.test.utils.js @@ -229,4 +229,68 @@ } return node; }; + + /** + * Like a reduced outerHTML serialization, but with a position marker '|'. + * + * For clarity, also wraps each text node in a fake tag, and omits non-class attributes. + * + * @param {Node} rootNode The node to serialize + * @param {Object} position + * @param {Node} position.node The node at which the position marker lies + * @param {number} position.offset The offset at which the position marker lies + * @param {Object} [options] + * @param {Function|string} options.ignore Selector for nodes to omit from output + * @returns {string} Serialization of the node and position + */ + ve.test.utils.serializePosition = function ( rootNode, position, options ) { + var html = []; + function add( node ) { + var i, len; + + if ( options && options.ignore && $( node ).is( options.ignore ) ) { + return; + } else if ( node.nodeType === Node.TEXT_NODE ) { + html.push( '<#text>' ); + if ( node === position.node ) { + html.push( ve.escapeHtml( + node.textContent.substring( 0, position.offset ) + + '|' + + node.textContent.substring( position.offset ) + ) ); + } else { + html.push( ve.escapeHtml( node.textContent ) ); + } + html.push( '</#text>' ); + return; + } else if ( node.nodeType !== Node.ELEMENT_NODE ) { + html.push( '<#unknown type=\'' + node.nodeType + '\'/>' ); + return; + } + // else node.nodeType === Node.ELEMENT_NODE + + html.push( '<', ve.escapeHtml( node.nodeName.toLowerCase() ) ); + if ( node.hasAttribute( 'class' ) ) { + // Single quotes are less annoying for JSON escaping + html.push( + ' class=\'', + ve.escapeHtml( node.getAttribute( 'class' ) ), + '\'' + ); + } + html.push( '>' ); + for ( i = 0, len = node.childNodes.length; i < len; i++ ) { + if ( node === position.node && i === position.offset ) { + html.push( '|' ); + } + add( node.childNodes[i] ); + } + if ( node === position.node && node.childNodes.length === position.offset ) { + html.push( '|' ); + } + html.push( '</', ve.escapeHtml( node.nodeName.toLowerCase() ), '>' ); + } + add( rootNode ); + return html.join( '' ); + }; }() ); -- To view, visit https://gerrit.wikimedia.org/r/206094 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8a211a19bd798e920c0800c9e8d7bd53cf5d49dd Gerrit-PatchSet: 1 Gerrit-Project: VisualEditor/VisualEditor Gerrit-Branch: master Gerrit-Owner: Divec <da...@sheetmusic.org.uk> Gerrit-Reviewer: Esanders <esand...@wikimedia.org> Gerrit-Reviewer: Jforrester <jforres...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits