mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 23:05:35 +00:00
b4f4eeb4b6
ve/ce/SurfaceObserver.js * Do not setTimeout if frequency === null demos/ve/eventLogger.html * Standalone event logging script ve/test/ce/imetests/*.js * JSON event logs for various tests/browsers/IMEs ve/test/ce/ve.ce.test.js * Add an IME test VisualEditor.hooks.php * Add test files Change-Id: I50e89d5a289f3fcb4fe2a6835a2ec96fb497242c
239 lines
7.5 KiB
JavaScript
239 lines
7.5 KiB
JavaScript
/*!
|
|
* VisualEditor ContentEditable tests.
|
|
*
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
QUnit.module( 've.ce' );
|
|
|
|
/* Tests */
|
|
|
|
QUnit.test( 'whitespacePattern', 4, function ( assert ) {
|
|
assert.equal( 'a b'.match( ve.ce.whitespacePattern ), ' ', 'matches spaces' );
|
|
assert.equal( 'a\u00A0b'.match( ve.ce.whitespacePattern ), '\u00A0', 'matches non-breaking spaces' );
|
|
assert.equal( 'a\tb'.match( ve.ce.whitespacePattern ), null, 'does not match tab' );
|
|
assert.equal( 'ab'.match( ve.ce.whitespacePattern ), null, 'does not match non-whitespace' );
|
|
} );
|
|
|
|
QUnit.test( 'getDomText', 1, function ( assert ) {
|
|
assert.equal( ve.ce.getDomText(
|
|
$( '<span>a<b><a href="#">b</a></b><span></span><i>c</i>d</span>' )[0] ),
|
|
'abcd'
|
|
);
|
|
} );
|
|
|
|
QUnit.test( 'getDomHash', 1, function ( assert ) {
|
|
assert.equal(
|
|
ve.ce.getDomHash( $( '<span>a<b><a href="#">b</a></b><span></span><i>c</i>d</span>' )[0] ),
|
|
'<SPAN>#<B><A>#</A></B><SPAN></SPAN><I>#</I>#</SPAN>'
|
|
);
|
|
} );
|
|
|
|
QUnit.test( 'getOffsetFrom(Element|Text)Node', function ( assert ) {
|
|
var i, surface, documentModel, documentView,
|
|
expected = 0,
|
|
testCases = [
|
|
{
|
|
'msg': 'Annotated alien',
|
|
'html': '<p>Foo<b><cite>Bar</cite></b>Baz</p>',
|
|
// CE html summary;
|
|
// <p>Foo<b><span [protectedNode]><cite>Bar</cite><img [shield]></span></b>Baz</p>
|
|
'expected': [
|
|
0,
|
|
1, 1,
|
|
2,
|
|
3,
|
|
4, 4, 4,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
7,
|
|
8,
|
|
9, 9,
|
|
10
|
|
]
|
|
}
|
|
];
|
|
|
|
for ( i = 0; i < testCases.length; i++ ) {
|
|
expected += testCases[i].expected.length;
|
|
}
|
|
|
|
QUnit.expect( expected );
|
|
|
|
function testOffsets( parent, testCase, expectedIndex ) {
|
|
var i;
|
|
switch ( parent.nodeType ) {
|
|
case Node.ELEMENT_NODE:
|
|
for ( i = 0; i <= parent.childNodes.length; i++ ) {
|
|
expectedIndex++;
|
|
assert.equal(
|
|
ve.ce.getOffsetFromElementNode( parent, i ),
|
|
testCase.expected[expectedIndex],
|
|
testCase.msg + ': offset ' + i + ' in <' + parent.nodeName.toLowerCase() + '>'
|
|
);
|
|
if ( parent.childNodes[i] ) {
|
|
expectedIndex = testOffsets( parent.childNodes[i], testCase, expectedIndex );
|
|
}
|
|
}
|
|
break;
|
|
case Node.TEXT_NODE:
|
|
for ( i = 0; i <= parent.data.length; i++ ) {
|
|
expectedIndex++;
|
|
assert.equal(
|
|
ve.ce.getOffsetFromTextNode( parent, i ),
|
|
testCase.expected[expectedIndex],
|
|
testCase.msg + ': offset ' + i + ' in "' + parent.data + '"'
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
return expectedIndex;
|
|
}
|
|
|
|
for ( i = 0; i < testCases.length; i++ ) {
|
|
surface = ve.test.utils.createSurfaceFromHtml( testCases[i].html );
|
|
documentModel = surface.getModel().getDocument();
|
|
documentView = surface.getView().getDocument();
|
|
|
|
testOffsets( documentView.documentNode.$element[0], testCases[i], -1 );
|
|
surface.destroy();
|
|
}
|
|
} );
|
|
|
|
// TODO: ve.ce.getOffset
|
|
|
|
// TODO: ve.ce.getOffsetOfSlug
|
|
|
|
QUnit.test( 'isLeftOrRightArrowKey', 4, function ( assert ) {
|
|
assert.equal( ve.ce.isLeftOrRightArrowKey( OO.ui.Keys.LEFT ), true, 'Left' );
|
|
assert.equal( ve.ce.isLeftOrRightArrowKey( OO.ui.Keys.RIGHT ), true, 'Right' );
|
|
assert.equal( ve.ce.isLeftOrRightArrowKey( OO.ui.Keys.UP ), false, 'Up' );
|
|
assert.equal( ve.ce.isLeftOrRightArrowKey( OO.ui.Keys.DOWN ), false, 'Down' );
|
|
} );
|
|
|
|
QUnit.test( 'isUpOrDownArrowKey', 4, function ( assert ) {
|
|
assert.equal( ve.ce.isUpOrDownArrowKey( OO.ui.Keys.LEFT ), false, 'Left' );
|
|
assert.equal( ve.ce.isUpOrDownArrowKey( OO.ui.Keys.RIGHT ), false, 'Right' );
|
|
assert.equal( ve.ce.isUpOrDownArrowKey( OO.ui.Keys.UP ), true, 'Up' );
|
|
assert.equal( ve.ce.isUpOrDownArrowKey( OO.ui.Keys.DOWN ), true, 'Down' );
|
|
} );
|
|
|
|
QUnit.test( 'isArrowKey', 5, function ( assert ) {
|
|
assert.equal( ve.ce.isArrowKey( OO.ui.Keys.LEFT ), true, 'Left' );
|
|
assert.equal( ve.ce.isArrowKey( OO.ui.Keys.RIGHT ), true, 'Right' );
|
|
assert.equal( ve.ce.isArrowKey( OO.ui.Keys.UP ), true, 'Up' );
|
|
assert.equal( ve.ce.isArrowKey( OO.ui.Keys.DOWN ), true, 'Down' );
|
|
assert.equal( ve.ce.isArrowKey( OO.ui.Keys.ENTER ), false, 'Enter' );
|
|
} );
|
|
|
|
QUnit.test( 'isShortcutKey', 3, function ( assert ) {
|
|
assert.equal( ve.ce.isShortcutKey( { 'ctrlKey': true } ), true, 'ctrlKey' );
|
|
assert.equal( ve.ce.isShortcutKey( { 'metaKey': true } ), true, 'metaKey' );
|
|
assert.equal( ve.ce.isShortcutKey( {} ), false, 'Not set' );
|
|
} );
|
|
|
|
QUnit.test( 'resolveTestOffset', function ( assert ) {
|
|
var i, ilen, j, jlen, tests, test, testOffset, elt, pre, post, count, dom;
|
|
tests = [
|
|
['o', 'k'],
|
|
// TODO: doesn't handle tags correctly yet!
|
|
// ['w', '<b>', 'x', 'y', '</b>', 'z'],
|
|
// ['q', '<b>', 'r', '<b>', 's', 't', '</b>', 'u', '</b>', 'v']
|
|
['h', 'e', 'l', 'l', 'o']
|
|
];
|
|
count = 0;
|
|
for ( i = 0, ilen = tests.length; i < ilen; i++ ) {
|
|
count += tests[i].length + 1;
|
|
}
|
|
QUnit.expect( 2 * count );
|
|
dom = ve.createDocumentFromHtml( '' );
|
|
elt = dom.createElement( 'div' );
|
|
for ( i = 0, ilen = tests.length; i < ilen; i++ ) {
|
|
test = tests[i];
|
|
elt.innerHTML = test.join( '' );
|
|
for ( j = 0, jlen = test.length; j < jlen + 1; j++ ) {
|
|
testOffset = new ve.ce.TestOffset( 'forward', j );
|
|
pre = test.slice( 0, j ).join( '' );
|
|
post = test.slice( j ).join( '' );
|
|
assert.equal(
|
|
testOffset.resolve( elt ).slice,
|
|
pre + '|' + post
|
|
);
|
|
testOffset = new ve.ce.TestOffset( 'backward', j );
|
|
pre = test.slice( 0, jlen - j ).join( '' );
|
|
post = test.slice( jlen - j ).join( '' );
|
|
assert.equal(
|
|
testOffset.resolve( elt ).slice,
|
|
pre + '|' + post
|
|
);
|
|
}
|
|
}
|
|
} );
|
|
|
|
QUnit.test( 'fakeImes', function ( assert ) {
|
|
var i, ilen, j, jlen, dom, target, testRunner, testName, testActions, seq, testInfo,
|
|
action, args, count, foundEndLoop, fakePreventDefault;
|
|
|
|
// count tests
|
|
count = 0;
|
|
for ( i = 0, ilen = ve.ce.imetests.length; i < ilen; i++ ) {
|
|
testName = ve.ce.imetests[i][0];
|
|
if ( ve.ce.imetestsBroken[testName] ) {
|
|
// Skip broken test for now
|
|
continue;
|
|
}
|
|
testActions = ve.ce.imetests[i][1];
|
|
// For the test that there is at least one endLoop
|
|
count++;
|
|
for ( j = 1, jlen = testActions.length; j < jlen; j++ ) {
|
|
action = testActions[j].action;
|
|
if ( action === 'endLoop' ) {
|
|
// For the test that the model and CE surface are in sync
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
if ( !count ) {
|
|
throw new Error( 'No IME tests found' );
|
|
}
|
|
QUnit.expect( count );
|
|
|
|
// TODO: make this function actually affect the events triggered
|
|
fakePreventDefault = function() {};
|
|
|
|
for ( i = 0, ilen = ve.ce.imetests.length; i < ilen; i++ ) {
|
|
testName = ve.ce.imetests[i][0];
|
|
if ( ve.ce.imetestsBroken[testName] ) {
|
|
// Skip broken test for now
|
|
continue;
|
|
}
|
|
testActions = ve.ce.imetests[i][1];
|
|
foundEndLoop = false;
|
|
// First element is the testInfo
|
|
testInfo = testActions[0];
|
|
dom = ve.createDocumentFromHtml( testInfo.startDom || '' );
|
|
target = new ve.init.sa.Target( $( '<div>' ).appendTo( '#qunit-fixture' ), dom );
|
|
testRunner = new ve.ce.TestRunner( target.surface );
|
|
// start at 1 to omit the testInfo
|
|
for ( j = 1, jlen = testActions.length; j < jlen; j++ ) {
|
|
action = testActions[j].action;
|
|
args = testActions[j].args;
|
|
seq = testActions[j].seq;
|
|
if ( action === 'sendEvent' ) {
|
|
// TODO: make preventDefault work
|
|
args[1].preventDefault = fakePreventDefault;
|
|
}
|
|
testRunner[action].apply( testRunner, args );
|
|
// Check synchronized at the end of each event loop
|
|
if ( action === 'endLoop' ) {
|
|
// Test that the model and CE surface are in sync
|
|
testRunner.testEqual( assert, testName, seq );
|
|
foundEndLoop = true;
|
|
}
|
|
}
|
|
// Test that there is at least one endLoop
|
|
assert.equal( foundEndLoop, true, testName + ' found at least one endLoop' );
|
|
target.surface.destroy();
|
|
}
|
|
} );
|