mediawiki-extensions-Visual.../modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
Catrope 04a999f991 Add change marking for Parsoid's benefit
* Add map of change markers per offset to Transaction
* Map is populated by TransactionProcessor
* Markers are reversed on rollback
* Removals aren't marked, Parsoid can detect these using DSR
  discontinuities

Change-Id: I2290886ab411c6ad6162044ed85c091313613e51
2012-11-06 10:11:11 -08:00

228 lines
8.1 KiB
JavaScript

/**
* VisualEditor data model SurfaceFragment tests.
*
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
QUnit.module( 've.dm.SurfaceFragment' );
// Tests
QUnit.test( 'constructor', 8, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface );
// Default range and autoSelect
assert.strictEqual( fragment.getSurface(), surface, 'surface reference is stored' );
assert.strictEqual( fragment.getDocument(), doc, 'document reference is stored' );
assert.deepEqual( fragment.getRange(), new ve.Range( 0, 0 ), 'range is taken from surface' );
assert.strictEqual( fragment.willAutoSelect(), true, 'auto select by default' );
assert.strictEqual( fragment.isNull(), false, 'valid fragment is not null' );
// Invalid range and autoSelect
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( -100, 100 ), 'truthy' );
assert.equal( fragment.getRange().from, 0, 'range is clamped between 0 and document length' );
assert.equal( fragment.getRange().to, 61, 'range is clamped between 0 and document length' );
assert.strictEqual( fragment.willAutoSelect(), false, 'noAutoSelect values are boolean' );
} );
QUnit.test( 'onTransact', 1, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment1 = new ve.dm.SurfaceFragment( surface, new ve.Range( 1, 56 ) ),
fragment2 = new ve.dm.SurfaceFragment( surface, new ve.Range( 2, 4 ) );
fragment1.removeContent();
assert.deepEqual(
fragment2.getRange(),
new ve.Range( 1, 1 ),
'fragment ranges are auto-translated when transactions are processed'
);
} );
QUnit.test( 'adjustRange', 3, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 20, 21 ) ),
adjustedFragment = fragment.adjustRange( -19, 35 );
assert.ok( fragment !== adjustedFragment, 'adjustRange produces a new fragment' );
assert.deepEqual( fragment.getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' );
assert.deepEqual( adjustedFragment.getRange(), new ve.Range( 1, 56 ), 'new range is used' );
} );
QUnit.test( 'collapseRange', 3, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 20, 21 ) ),
collapsedFragment = fragment.collapseRange();
assert.ok( fragment !== collapsedFragment, 'collapseRange produces a new fragment' );
assert.deepEqual( fragment.getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' );
assert.deepEqual( collapsedFragment.getRange(), new ve.Range( 20, 20 ), 'new range is used' );
} );
QUnit.test( 'expandRange', 1, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 20, 21 ) );
assert.strictEqual(
fragment.expandRange( 'closest', 'invalid type' ).isNull(),
true,
'closest with invalid type results in null fragment'
);
} );
QUnit.test( 'removeContent', 2, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 1, 56 ) ),
expectedData = ve.copyArray( ve.dm.example.data.slice( 0, 1 ) )
.concat( ve.copyArray( ve.dm.example.data.slice( 4, 5 ) ) )
.concat( ve.copyArray( ve.dm.example.data.slice( 55 ) ) );
ve.setProp( expectedData[0], 'internal', 'changed', 'content', 1 );
fragment.removeContent();
assert.deepEqual(
doc.getData(),
expectedData,
'removing content drops fully covered nodes and strips partially covered ones'
);
assert.deepEqual(
fragment.getRange(),
new ve.Range( 1, 1 ),
'removing content results in a zero-length fragment'
);
} );
QUnit.test( 'insertContent', 3, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 1, 4 ) );
fragment.insertContent( ['1', '2', '3'] );
assert.deepEqual(
doc.getData( new ve.Range( 1, 4 ) ),
['1', '2', '3'],
'inserting content replaces selection with new content'
);
assert.deepEqual(
fragment.getRange(),
new ve.Range( 4, 4 ),
'inserting content results in a zero-length fragment'
);
fragment.insertContent( '321' );
assert.deepEqual(
doc.getData( new ve.Range( 4, 7 ) ),
['3', '2', '1'],
'strings get converted into data when inserting content'
);
} );
QUnit.test( 'wrapNodes', 2, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 55, 61 ) );
// Make 2 paragraphs into 2 lists of 1 item each
fragment.wrapNodes(
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
);
assert.deepEqual(
doc.getData( new ve.Range( 55, 69 ) ),
[
{
'type': 'list',
'attributes': { 'style': 'bullet' },
'internal': { 'changed': { 'created': 1 } }
},
{ 'type': 'listItem', 'internal': { 'changed': { 'created': 1 } } },
{ 'type': 'paragraph' },
'l',
{ 'type': '/paragraph' },
{ 'type': '/listItem' },
{ 'type': '/list' },
{
'type': 'list',
'attributes': { 'style': 'bullet' },
'internal': { 'changed': { 'created': 1 } }
},
{ 'type': 'listItem', 'internal': { 'changed': { 'created': 1 } } },
{ 'type': 'paragraph' },
'm',
{ 'type': '/paragraph' },
{ 'type': '/listItem' },
{ 'type': '/list' }
],
'wrapping nodes can add multiple levels of wrapping to multiple elements'
);
// Make a 1 paragraph into 1 list with 1 item
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
fragment.wrapNodes(
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
);
assert.deepEqual(
doc.getData( new ve.Range( 9, 16 ) ),
[
{
'type': 'list',
'attributes': { 'style': 'bullet' },
'internal': { 'changed': { 'created': 1 } }
},
{ 'type': 'listItem', 'internal': { 'changed': { 'created': 1 } } },
{ 'type': 'paragraph' },
'd',
{ 'type': '/paragraph' },
{ 'type': '/listItem' },
{ 'type': '/list' }
],
'wrapping nodes can add multiple levels of wrapping to a single element'
);
} );
QUnit.test( 'wrapAllNodes', 2, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
surface = new ve.dm.Surface( doc ),
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 55, 61 ) );
// Make 2 paragraphs into 1 lists of 1 item with 2 paragraphs
fragment.wrapAllNodes(
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
);
assert.deepEqual(
doc.getData( new ve.Range( 55, 65 ) ),
[
{
'type': 'list',
'attributes': { 'style': 'bullet' },
'internal': { 'changed': { 'created': 1 } }
},
{ 'type': 'listItem', 'internal': { 'changed': { 'created': 1 } } },
{ 'type': 'paragraph' },
'l',
{ 'type': '/paragraph' },
{ 'type': 'paragraph' },
'm',
{ 'type': '/paragraph' },
{ 'type': '/listItem' },
{ 'type': '/list' }
],
'wrapping nodes can add multiple levels of wrapping to multiple elements'
);
// Make a 1 paragraph into 1 list with 1 item
fragment = new ve.dm.SurfaceFragment( surface, new ve.Range( 9, 12 ) );
fragment.wrapAllNodes(
[{ 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }]
);
assert.deepEqual(
doc.getData( new ve.Range( 9, 16 ) ),
[
{
'type': 'list',
'attributes': { 'style': 'bullet' },
'internal': { 'changed': { 'created': 1 } }
},
{ 'type': 'listItem', 'internal': { 'changed': { 'created': 1 } } },
{ 'type': 'paragraph' },
'd',
{ 'type': '/paragraph' },
{ 'type': '/listItem' },
{ 'type': '/list' }
],
'wrapping nodes can add multiple levels of wrapping to a single element'
);
} );