mediawiki-extensions-Visual.../modules/ve-mw/test/dm/ve.dm.Transaction.test.js
Roan Kattouw 64e5016423 Fix metadata issues in newFromDocumentReplace
* Our metadata insertions now need to be the same length as the data
  insertion, not one more, so:
** Remove the +1 in the listMetadata splice
** Shorten the metadata variable by dropping the merging of the
   metadata right before and right after the internal list; it was
   also including the metadata right after the internal list twice
*** We still need to deal with this in some way though, left a TODO
** Fix the metadata insertion test for these changes
* Fix null reference keys in the test data; we made all references
  keyed a while ago, but this test data was never updated for that
** The remapping of reference data doesn't remap auto/N keys yet,
   left a FIXME for that

Change-Id: I8ef4e6ee7c1808574d81d0b83294848afd400cd7
2013-11-04 14:37:26 +00:00

145 lines
5 KiB
JavaScript

/*!
* VisualEditor DataModel Transaction tests.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
QUnit.module( 've.dm.Transaction' );
// FIXME duplicates test runner; should be using a data provider
QUnit.test( 'newFromDocumentReplace with references', function ( assert ) {
var i, j, doc2, tx, actualStoreItems, expectedStoreItems,
doc = ve.dm.example.createExampleDocument( 'internalData' ),
complexDoc = ve.dm.mwExample.createExampleDocument( 'complexInternalData' ),
comment = { 'type': 'alienMeta', 'attributes': { 'domElements': $( '<!-- hello -->' ).get() } },
withReference = [
{ 'type': 'paragraph' },
'B', 'a', 'r',
{ 'type': 'mwReference', 'attributes': {
'mw': {},
'about': '#mwt4',
'listIndex': 0,
'listGroup': 'mwReference/',
'listKey': 'auto/1', // FIXME reference insertions should be renumbered correctly
'refGroup': '',
'contentsUsed': true
} },
{ 'type': '/mwReference' },
{ 'type': '/paragraph' },
{ 'type': 'internalList' },
{ 'type': 'internalItem' },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'B',
'a',
'z',
{ 'type': '/paragraph' },
{ 'type': '/internalItem' },
{ 'type': '/internalList' }
],
cases = [
{
'msg': 'metadata insertion',
'doc': complexDoc,
'range': new ve.Range( 0, 7 ),
'modify': function ( newDoc ) {
newDoc.commit( ve.dm.Transaction.newFromMetadataInsertion(
newDoc, 5, 0, [ comment ]
) );
},
'expectedOps': [
{
'type': 'replace',
'remove': complexDoc.getData( new ve.Range( 0, 7 ) ),
'insert': complexDoc.getData( new ve.Range( 0, 7 ) ),
'removeMetadata': complexDoc.getMetadata( new ve.Range( 0, 7 ) ),
'insertMetadata': complexDoc.getMetadata( new ve.Range( 0, 5 ) )
.concat( [ [ comment ] ] )
.concat( complexDoc.getMetadata( new ve.Range( 6, 7 ) ) )
},
{ 'type': 'retain', 'length': 1 },
{
'type': 'replace',
'remove': complexDoc.getData( new ve.Range( 8, 32 ) ),
'insert': complexDoc.getData( new ve.Range( 8, 32 ) ),
'removeMetadata': complexDoc.getMetadata( new ve.Range( 8, 32 ) ),
'insertMetadata': complexDoc.getMetadata( new ve.Range( 8, 32 ) )
},
{ 'type': 'retain', 'length': 1 }
]
},
{
'msg': 'metadata removal',
'doc': complexDoc,
'range': new ve.Range( 24, 31 ),
'modify': function ( newDoc ) {
newDoc.commit( ve.dm.Transaction.newFromMetadataRemoval(
newDoc, 6, new ve.Range( 0, 1 )
) );
},
'expectedOps': [
{ 'type': 'retain', 'length': 8 },
{
'type': 'replace',
'remove': complexDoc.getData( new ve.Range( 8, 32 ) ),
'insert': complexDoc.getData( new ve.Range( 8, 32 ) ),
'removeMetadata': complexDoc.getMetadata( new ve.Range( 8, 32 ) ),
'insertMetadata': complexDoc.getMetadata( new ve.Range( 8, 30 ) )
.concat( [ [] ] )
.concat( complexDoc.getMetadata( new ve.Range( 31, 32 ) ) )
},
{ 'type': 'retain', 'length': 1 }
]
},
{
'msg': 'inserting a brand new document; internal lists are merged and items renumbered',
'doc': complexDoc,
'range': new ve.Range( 7, 7 ),
'newDocData': withReference,
'expectedOps': [
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [],
'insert': withReference.slice( 0, 4 )
// Renumber listIndex from 0 to 2
.concat( [ ve.extendObject( true, {}, withReference[4],
{ 'attributes': { 'listIndex': 2 } } ) ] )
.concat( withReference.slice( 5, 7 ) )
},
{ 'type': 'retain', 'length': 1 },
{
'type': 'replace',
'remove': complexDoc.getData( new ve.Range( 8, 32 ) ),
'insert': complexDoc.getData( new ve.Range( 8, 32 ) )
.concat( withReference.slice( 8, 15 ) ),
'removeMetadata': complexDoc.getMetadata( new ve.Range( 8, 32 ) ),
'insertMetadata': complexDoc.getMetadata( new ve.Range( 8, 32 ) )
.concat( new Array( 7 ) )
},
{ 'type': 'retain', 'length': 1 }
]
}
];
QUnit.expect( 2 * cases.length );
for ( i = 0; i < cases.length; i++ ) {
doc = cases[i].doc; // TODO deep copy?
if ( cases[i].newDocData ) {
doc2 = new ve.dm.Document( cases[i].newDocData );
} else {
doc2 = doc.cloneFromRange( cases[i].range instanceof ve.Range ? cases[i].range : cases[i].range.getRange() );
cases[i].modify( doc2 );
}
tx = ve.dm.Transaction.newFromDocumentReplace( doc, cases[i].range, doc2 );
assert.deepEqualWithDomElements( tx.getOperations(), cases[i].expectedOps, cases[i].msg + ': transaction' );
actualStoreItems = [];
expectedStoreItems = cases[i].expectedStoreItems || [];
for ( j = 0; j < expectedStoreItems.length; j++ ) {
actualStoreItems[j] = doc.store.value( doc.store.indexOfHash(
OO.getHash( expectedStoreItems[j] )
) );
}
assert.deepEqual( actualStoreItems, expectedStoreItems, cases[i].msg + ': store items' );
}
} );