/*!
* VisualEditor Base method tests.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
QUnit.module( 've' );
/* Tests */
// ve.cloneObject: Tested upstream (OOJS)
// ve.getObjectValues: Tested upstream (OOJS)
// ve.getObjectKeys: Tested upstream (JavaScript)
// ve.compare: Tested upstream (OOJS)
// ve.copy: Tested upstream (OOJS)
// ve.isPlainObject: Tested upstream (jQuery)
// ve.isEmptyObject: Tested upstream (jQuery)
// ve.isArray: Tested upstream (jQuery)
// ve.bind: Tested upstream (jQuery)
// ve.indexOf: Tested upstream (jQuery)
// ve.extendObject: Tested upstream (jQuery)
QUnit.test( 'getHash: Basic usage', 7, function ( assert ) {
var tmp,
cases = {},
hash = '{"a":1,"b":1,"c":1}',
customHash = '{"first":1,"last":1}';
cases['a-z literal'] = {
object: {
a: 1,
b: 1,
c: 1
},
hash: hash
};
cases['z-a literal'] = {
object: {
c: 1,
b: 1,
a: 1
},
hash: hash
};
tmp = {};
cases['a-z augmented'] = {
object: tmp,
hash: hash
};
tmp.a = 1;
tmp.b = 1;
tmp.c = 1;
tmp = {};
cases['z-a augmented'] = {
object: tmp,
hash: hash
};
tmp.c = 1;
tmp.b = 1;
tmp.a = 1;
cases['custom hash'] = {
object: {
getHashObject: function () {
return {
'first': 1,
'last': 1
};
}
},
hash: customHash
};
cases['custom hash reversed'] = {
object: {
getHashObject: function () {
return {
'last': 1,
'first': 1
};
}
},
hash: customHash
};
$.each( cases, function ( key, val ) {
assert.equal(
ve.getHash( val.object ),
val.hash,
key + ': object has expected hash, regardless of "property order"'
);
} );
// .. and that something completely different is in face different
// (just incase getHash is broken and always returns the same)
assert.notEqual(
ve.getHash( { a: 2, b: 2 } ),
hash,
'A different object has a different hash'
);
} );
QUnit.test( 'getHash: Complex usage', 3, function ( assert ) {
var obj, hash, frame;
obj = {
a: 1,
b: 1,
c: 1,
// Nested array
d: ['x', 'y', 'z'],
e: {
a: 2,
b: 2,
c: 2
}
};
assert.equal(
ve.getHash( obj ),
'{"a":1,"b":1,"c":1,"d":["x","y","z"],"e":{"a":2,"b":2,"c":2}}',
'Object with nested array and nested object'
);
// Include a circular reference
/*
* PhantomJS hangs when calling JSON.stringify with an object containing a
* circular reference (https://github.com/ariya/phantomjs/issues/11206).
* We know latest Chrome/Firefox and IE8+ support this. So, for the sake of
* having qunit/phantomjs work, lets disable this for now.
obj.f = obj;
assert.throws( function () {
ve.getHash( obj );
}, 'Throw exceptions for objects with cirular refences ' );
*/
function Foo() {
this.a = 1;
this.c = 3;
this.b = 2;
}
hash = '{"a":1,"b":2,"c":3}';
assert.equal(
ve.getHash( new Foo() ),
hash,
// This was previously broken when we used .constructor === Object
// ve.getHash.keySortReplacer, because although instances of Foo
// do inherit from Object (( new Foo() ) instanceof Object === true),
// direct comparison would return false.
'Treat objects constructed by a function as well'
);
frame = document.createElement( 'frame' );
frame.src = 'about:blank';
$( '#qunit-fixture' ).append( frame );
obj = new frame.contentWindow.Object();
obj.c = 3;
obj.b = 2;
obj.a = 1;
assert.equal(
ve.getHash( obj ),
hash,
// This was previously broken when we used comparison with "Object" in
// ve.getHash.keySortReplacer, because they are an instance of the other
// window's "Object".
'Treat objects constructed by a another window as well'
);
} );
QUnit.test( 'getDomAttributes', 1, function ( assert ) {
assert.deepEqual(
ve.getDomAttributes( $( '
' ).get( 0 ) ),
{ 'foo': 'bar', 'baz': '', 'quux': '3' },
'getDomAttributes() returns object with correct attributes'
);
} );
QUnit.test( 'setDomAttributes', 3, function ( assert ) {
var element = document.createElement( 'div' );
ve.setDomAttributes( element, { 'foo': 'bar', 'baz': '', 'quux': 3 } );
assert.deepEqual(
ve.getDomAttributes( element ),
{ 'foo': 'bar', 'baz': '', 'quux': '3' },
'setDomAttributes() sets attributes correctly'
);
ve.setDomAttributes( element, { 'foo': null, 'bar': 1, 'baz': undefined, 'quux': 5, 'whee': 'yay' } );
assert.deepEqual(
ve.getDomAttributes( element ),
{ 'bar': '1', 'quux': '5', 'whee': 'yay' },
'setDomAttributes() overwrites attributes, removes attributes, and sets new attributes'
);
ve.setDomAttributes( element, { 'onclick': 'alert(1);' }, ['foo', 'bar', 'baz', 'quux', 'whee'] );
assert.ok( !element.hasAttribute( 'onclick' ), 'event attributes are blocked when sanitizing' );
} );
QUnit.test( 'getOpeningHtmlTag', 5, function ( assert ) {
assert.deepEqual(
ve.getOpeningHtmlTag( 'code', {} ),
'',
'opening tag without attributes'
);
assert.deepEqual(
ve.getOpeningHtmlTag( 'img', { 'src': 'foo' } ),
'',
'opening tag with one attribute'
);
assert.deepEqual(
ve.getOpeningHtmlTag( 'a', { 'href': 'foo', 'rel': 'bar' } ),
'',
'tag with two attributes'
);
assert.deepEqual(
ve.getOpeningHtmlTag( 'option', { 'selected': true, 'blah': false, 'value': 3 } ),
'