mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-29 08:34:54 +00:00
164 lines
4.9 KiB
JavaScript
164 lines
4.9 KiB
JavaScript
|
/**
|
||
|
* VisualEditor CommandFactory tests.
|
||
|
*
|
||
|
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
|
||
|
* @license The MIT License (MIT); see LICENSE.txt
|
||
|
*/
|
||
|
|
||
|
( function () {
|
||
|
// When runSequence is called multiple times,
|
||
|
// be sure to keep track of how far in the future we've scheduled,
|
||
|
// since mixed sequences are (intentionally) invalidated.
|
||
|
var sequenceSimulatorOffset = 0;
|
||
|
|
||
|
QUnit.module( 've.ui.CommandFactory', {
|
||
|
setup: function () {
|
||
|
// Clear registry after each test
|
||
|
ve.ui.commandFactory = new ve.ui.CommandFactory();
|
||
|
},
|
||
|
teardown: function () {
|
||
|
// Can't restore because the constructor does .off(), so the
|
||
|
// old one is destroyed
|
||
|
ve.ui.commandFactory = new ve.ui.CommandFactory();
|
||
|
}
|
||
|
} );
|
||
|
|
||
|
/**
|
||
|
* @param {string|undefined} action
|
||
|
* @param {string} char Single character.
|
||
|
* @param {Object} props [optional]
|
||
|
*/
|
||
|
function runAction( action, char, props ) {
|
||
|
props = props || {};
|
||
|
props.which = char.charCodeAt( 0 );
|
||
|
|
||
|
$( 'body' ).trigger(
|
||
|
$.Event( action || 'keypress', props )
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} action
|
||
|
* @param {number} interval Time between actions (in milliseconds).
|
||
|
* @param {string} chars
|
||
|
*/
|
||
|
function runSequence( action, interval, chars ) {
|
||
|
var i;
|
||
|
|
||
|
chars = chars.split( ' ' );
|
||
|
|
||
|
/**
|
||
|
* Utility function to avoid making functions
|
||
|
* in a loop, causing scope issues with 'i'.
|
||
|
*/
|
||
|
function schedule( char, delay ) {
|
||
|
setTimeout( function () {
|
||
|
runAction( action, char );
|
||
|
}, delay );
|
||
|
}
|
||
|
|
||
|
for ( i = 0; i < chars.length; i++ ) {
|
||
|
sequenceSimulatorOffset += interval;
|
||
|
schedule( chars[i], sequenceSimulatorOffset );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QUnit.test( 'register: Single characters', 18, function ( assert ) {
|
||
|
$.each( {
|
||
|
// Default should work with keypress
|
||
|
'default': [ undefined, 'keypress' ],
|
||
|
'keypress': [ 'keypress', 'keypress' ]
|
||
|
}, function ( action, event ) {
|
||
|
$.each( '0 9 a Z ! > - +'.split( ' ' ), function ( i, char ) {
|
||
|
ve.ui.commandFactory.register( char, function () {
|
||
|
assert.ok( true, action + ': "' + char + '" - ' + event[1] + ' trigger without modifier keys' );
|
||
|
}, event[0] );
|
||
|
|
||
|
runAction( event[1], char );
|
||
|
|
||
|
} );
|
||
|
} );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'a', function () {
|
||
|
assert.ok( false, 'keypress: "a" - trigger A is ignored' );
|
||
|
}, 'keypress' );
|
||
|
runAction( 'keypress', 'A' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'a', function () {
|
||
|
assert.ok( false, 'keypress: "a" - trigger A with Shift is ignored' );
|
||
|
}, 'keypress' );
|
||
|
runAction( 'keypress', 'A', { shiftKey: true } );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'Z', function () {
|
||
|
assert.ok( true, 'keypress: "Z" - trigger Z with Shift' );
|
||
|
}, 'keypress' );
|
||
|
runAction( 'keypress', 'Z', { shiftKey: true } );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'g', function () {
|
||
|
assert.ok( false, 'keypress: "g" - register removes old callbacks' );
|
||
|
}, 'keypress' );
|
||
|
ve.ui.commandFactory.register( 'g', function () {
|
||
|
// Undocumented behavior, tested so we detect if/when it changes
|
||
|
assert.ok( true, 'keypress: "g" - register keeps only the last callback' );
|
||
|
}, 'keypress' );
|
||
|
runAction( 'keypress', 'g' );
|
||
|
|
||
|
} );
|
||
|
|
||
|
QUnit.asyncTest( 'register: Sequences', 3, function ( assert ) {
|
||
|
ve.ui.commandFactory.register( '1 2 3', function () {
|
||
|
assert.ok( true, 'Number sequence with 20ms interval' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 20, '1 2 3' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'a b c Z', function () {
|
||
|
assert.ok( true, 'Letter sequence with 10ms interval' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 10, 'a b c Z' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'o r d e r', function () {
|
||
|
assert.ok( false, 'Out of order is invalid' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 10, 'o r d r e' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'm i s s', function () {
|
||
|
assert.ok( false, 'Missing in-between is invalid' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 10, 'm s s' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'e x t', function () {
|
||
|
assert.ok( false, 'Extra in-between is invalid' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 10, 'e r x t' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 's l', function () {
|
||
|
assert.ok( true, 'Total sequence may take over a second (2 * 600ms)' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 600, 's l' );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'g a', function () {
|
||
|
assert.ok( false, 'Sequences with gaps > 1 second are invalid (2 x 1100ms)' );
|
||
|
} );
|
||
|
runSequence( 'keypress', 1100, 'g a' );
|
||
|
|
||
|
setTimeout( QUnit.start, sequenceSimulatorOffset + 1 );
|
||
|
} );
|
||
|
|
||
|
QUnit.test( 'register: Combinations', 2, function ( assert ) {
|
||
|
ve.ui.commandFactory.register( 'ctrl+i', function ( e, combo ) {
|
||
|
assert.ok( true, combo );
|
||
|
} );
|
||
|
|
||
|
// XXX: Apparently i/ctrl doesn't work, needs to be uppercase I.
|
||
|
// This is internally normalized back to 'a'.
|
||
|
// Google Chrome (and others) use keycode for 'A' when typing a + modifier.
|
||
|
runAction( 'keydown', 'I', { ctrlKey: true } );
|
||
|
|
||
|
ve.ui.commandFactory.register( 'cmd+b', function ( e, combo ) {
|
||
|
assert.ok( true, combo );
|
||
|
} );
|
||
|
runAction( 'keydown', 'B', { metaKey: true } );
|
||
|
} );
|
||
|
|
||
|
}() );
|