001.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Microdata tests</title>
<script type="text/javascript" src="/resources/testharness.js"></script>
<script type="text/javascript" src="/resources/testharnessreport.js"></script>
<link rel="help" href="http://dev.w3.org/html5/md/#microdata-dom-api">
<link rel="help" href="http://dev.w3.org/html5/md/#encoding-microdata">
</head>
<body>
<noscript><p>Enable JavaScript and reload</p></noscript>
<div id="log">Running test...</div>
<div itemscope itemtype="http://example.com/bar data:text/plain, http://example.com/foo" id="one"></div>
<div itemscope itemtype="http://example.com/bar" id="two"></div>
<div itemscope itemtype="http://example.com/foo http://example.com/bar" id="three">
<div itemscope itemtype="http://example.com/bar data:text/plain," id="four"></div>
</div>
<div itemscope id="five"></div>
<script type="text/javascript">
/* All tests are stand-alone.
To reduce this testsuite to show only a single desired test,
simply remove all test(...) blocks before and after it. */
function makeEl(eltype,props,contents) {
var elem = document.createElement(eltype);
for( var i in props ) {
//just in case the framework extends object...
if( props.hasOwnProperty(i) ) {
elem.setAttribute(i,props[i]);
}
}
if( contents ) {
elem.innerHTML = contents;
}
return elem;
}
/* getItem tests */
test(function () {
assert_true( !!document.getItems );
}, 'document.getItems must exist');
test(function () {
assert_true( document.getItems() instanceof NodeList, 'instanceof test' );
NodeList.prototype.customProperty = true;
assert_true( document.getItems().customProperty, 'inheritance test' );
}, 'document.getItems must return a NodeList');
test(function () {
assert_equals( document.getItems().length, 5 );
}, 'document.getItems must locate the correct number of items');
test(function () {
var nlist = document.getItems();
var foo = makeEl('div',{itemscope:'itemscope'});
document.body.appendChild(foo);
var templength = nlist.length;
document.body.removeChild(foo);
assert_equals( templength, 6 );
assert_equals( nlist.length, 5 );
}, 'document.getItems must return a live NodeList');
test(function () {
var nlist = document.getItems();
document.getElementById('one').removeAttribute('itemscope');
var templength = nlist.length;
document.getElementById('one').setAttribute('itemscope','itemscope');
assert_equals( templength, 4 );
assert_equals( nlist.length, 5 );
}, 'live NodeList must notice when itemscope changes');
test(function () {
document.getElementById('one').removeAttribute('itemscope');
var templength = document.getItems().length;
document.getElementById('one').setAttribute('itemscope','itemscope');
assert_equals( templength, 4 );
assert_equals( document.getItems().length, 5 );
}, 'next request must notice when itemscope changes');
test(function () {
assert_equals( document.getItems('http://example.com/').length, 0, 'http://example.com/' );
assert_equals( document.getItems('example').length, 0, 'example' );
assert_equals( document.getItems('http://example.com/foo').length, 2, 'http://example.com/foo' );
assert_equals( document.getItems('http://example.com/bar').length, 4, 'http://example.com/bar' );
assert_equals( document.getItems('data:text/plain,').length, 2, 'data:text/plain,' );
}, 'document.getItems must locate the right number of items for each itemtype');
test(function () {
assert_equals( document.getItems('http://example.com/Foo').length, 0, 'http://example.com/Foo' );
assert_equals( document.getItems('HTTP://example.com/foo').length, 0, 'HTTP://example.com/foo' );
}, 'document.getItems must be case sensitive');
test(function () {
var nlist = document.getItems('http://example.com/foo');
var foo = makeEl('div',{itemscope:'itemscope',itemtype:'http://example.com/foo'});
document.body.appendChild(foo);
var templength = nlist.length;
document.body.removeChild(foo);
assert_equals( templength, 3 );
assert_equals( nlist.length, 2 );
}, 'document.getItems must return a live NodeList when using URLs');
test(function () {
var nlist = document.getItems('http://example.com/foo');
document.getElementById('one').removeAttribute('itemtype');
var templength = nlist.length;
document.getElementById('one').setAttribute('itemtype','http://example.com/bar data:text/plain, http://example.com/foo');
assert_equals( templength, 1 );
assert_equals( nlist.length, 2 );
}, 'live NodeList must notice when itemtype changes');
test(function () {
document.getElementById('one').removeAttribute('itemtype');
var templength = document.getItems('http://example.com/foo').length;
document.getElementById('one').setAttribute('itemtype','http://example.com/bar data:text/plain, http://example.com/foo');
assert_equals( templength, 1 );
assert_equals( document.getItems('http://example.com/foo').length, 2 );
}, 'next request must notice when itemtype changes');
test(function () {
assert_equals( document.getItems('http://example.com/foo data:text/plain,').length, 1, 'basic spaces' );
assert_equals( document.getItems(' http://example.com/foo data:text/plain, ').length, 1, 'extraneous spaces' );
}, 'document.getItems must locate items when parameters are separated by spaces');
test(function () {
assert_equals( document.getItems('http://example.com/foo data:text/plain, http://example.com/foo').length, 1 );
}, 'document.getItems must ignore duplicated tokens');
test(function () {
var testitems = document.getItems('http://example.com/bar');
assert_equals( testitems[0].id, 'one' );
assert_equals( testitems[1].id, 'two' );
assert_equals( testitems[2].id, 'three' );
assert_equals( testitems[3].id, 'four' );
}, 'document.getItems NodeList must be in source tree order');
test(function () {
assert_true( document.getItems('http://example.com/abc') != document.getItems('http://example.com/def'), 'different tokens' );
assert_true( document.getItems() != document.getItems(' '), 'no tokens' );
}, 'document.getItems must not return the same NodeList for different parameters');
test(function () {
assert_equals( document.getItems('').length, 5, 'empty string' );
assert_equals( document.getItems(' ').length, 5, 'string with spaces' );
}, 'document.getItems must treat no tokens as no parameter');
//removed due to disputed Web compatibility of casting null with DOM methods
/*
test(function () {
assert_equals( document.getItems(null).length, 0, 'null' );
assert_equals( document.getItems(window.undefined).length, 0, 'undefined' );
}, 'document.getItems must cast null and undefined to strings');
*/
test(function () {
var foo = makeEl('div',{itemtype:'http://example.com/foo'});
document.body.appendChild(foo);
var templength = document.getItems('http://example.com/foo').length;
document.body.removeChild(foo);
assert_equals( templength, 2 );
}, 'document.getItems must not find items with itemtype but not itemscope');
test(function () {
var foo = makeEl('div',{itemscope:'itemscope',itemtype:'baz'}),
bar = makeEl('div',{itemscope:'itemscope',itemtype:location.href.replace(/\/[^\/]*$/,'/baz')});
document.body.appendChild(foo);
document.body.appendChild(bar);
var unrezlength = document.getItems('baz').length;
var rezlength = document.getItems(location.href.replace(/\/[^\/]*$/,'/baz')).length;
document.body.removeChild(foo);
document.body.removeChild(bar);
assert_equals( unrezlength, 1, 'unresolved URL' );
assert_equals( rezlength, 1, 'resolved URL' );
}, 'document.getItems and itemtype must not resolve URLs');
test(function () {
document.getElementById('one').setAttribute('itemprop','test');
document.getElementById('four').setAttribute('itemprop','test');
var templength = document.getItems().length;
document.getElementById('one').removeAttribute('itemprop');
document.getElementById('four').removeAttribute('itemprop');
assert_equals( templength, 3 );
}, 'document.getItems must not see items that have the itemprop attribute set');
/* itemScope property tests */
test(function () {
assert_true(makeEl('div',{itemscope:'itemscope'}).itemScope);
assert_false(makeEl('div',{}).itemScope);
}, 'the itemscope attribute must be reflected by the .itemScope property');
test(function () {
assert_equals( typeof makeEl('div',{itemscope:'itemscope'}).itemScope, 'boolean', 'attribute exists' );
assert_equals( typeof makeEl('div',{}).itemScope, 'boolean', 'attribute does not exist' );
}, 'the itemScope property must be boolean');
test(function () {
var testEl = makeEl('div',{});
testEl.itemScope = true;
assert_true(testEl.itemScope,'writing true');
testEl.itemScope = false;
assert_false(testEl.itemScope,'writing false');
}, 'the itemScope property must be read/write');
test(function () {
var testEl = makeEl('div',{});
testEl.itemScope = true;
assert_true(testEl.hasAttribute('itemscope'),'writing true');
testEl.itemScope = false;
assert_false(testEl.hasAttribute('itemscope'),'writing false');
}, 'writing to the itemScope property must toggle existence of the itemscope content attribute');
test(function () {
var testEl = makeEl('div',{});
document.body.appendChild(testEl);
var numAppend = document.getItems().length;
testEl.itemScope = true;
var numTrue = document.getItems().length;
testEl.itemScope = false;
var numFalse = document.getItems().length;
document.body.removeChild(testEl);
assert_equals(numAppend,5,'after appending the new item');
assert_equals(numTrue,6,'after setting the property to true');
assert_equals(numFalse,5,'after setting the property to false');
}, 'writing to the itemScope property must affect whether the element is returned by getItems');
test(function () {
var testEl = makeEl('div',{}), nlist = document.getItems();
document.body.appendChild(testEl);
var numAppend = nlist.length;
testEl.itemScope = true;
var numTrue = nlist.length;
testEl.itemScope = false;
var numFalse = nlist.length;
document.body.removeChild(testEl);
assert_equals(numAppend,5,'after appending the new item');
assert_equals(numTrue,6,'after setting the property to true');
assert_equals(numFalse,5,'after setting the property to false');
}, 'writing to the itemScope property must affect membership of live NodeLists');
/* itemType property tests (properties collection tests are done later) */
test(function () {
assert_equals(makeEl('div',{}).itemType.toString(),'','no attribute');
assert_equals(makeEl('div',{itemtype:' foo bar '}).itemType.toString(),' foo bar ','with simple tokens');
var testEl = makeEl('div',{itemtype:'foo'});
testEl.removeAttribute('itemtype');
assert_equals(testEl.itemType.toString(),'','removed attribute');
}, 'the itemType attribute must be reflected by the .itemRef property');
test(function () {
assert_equals( typeof makeEl('div',{}).itemType, 'object' );
}, 'the itemType property must be an object');
test(function () {
assert_true( makeEl('div',{}).itemType instanceof DOMTokenList, 'instanceof test' );
DOMTokenList.prototype.customProperty = true;
assert_true( makeEl('div',{}).itemType.customProperty, 'inheritance test' );
}, 'the itemType property must implement DOMTokenList');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.itemType, testEl.itemType );
}, 'the itemType property must always reference the same object');
test(function () {
assert_equals( makeEl('div',{itemtype:'test test'}).itemType.length, 2, 'duplicates in initial string should be preserved' );
assert_equals( makeEl('div',{itemtype:'test test'}).itemType.item(0), 'test' );
assert_true( makeEl('div',{itemtype:'test test'}).itemType.contains('test') );
}, 'itemType must be correct for an element that has itemtype tokens');
test(function () {
assert_equals( makeEl('div',{itemtype:' '}).itemType.length, 0 );
}, 'itemType.length must be 0 for an element that has no tokens');
test(function () {
assert_false( makeEl('div',{itemtype:' '}).itemType.contains('foo') );
}, 'itemType must not contain an undefined class');
test(function () {
assert_equals( makeEl('div',{itemtype:' '}).itemType.item(0), null );
}, 'itemType.item() must return null for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemtype:' '}).itemType.item(-1), null );
}, 'itemType.item() must return null for negative index');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemtype:' '}).itemType[0], window.undefined );
}, 'itemType[index] must be undefined for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemtype:' '}).itemType[-1], window.undefined );
}, 'itemType[index] must be undefined for negative index');
test(function () {
assert_equals( makeEl('div',{itemType:' '}).itemType.toString(), ' ' );
}, 'empty itemType should stringify to contain the attribute\'s whitespace');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.contains(''); } );
}, 'itemType.contains(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.add(''); } );
}, 'itemType.add(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.remove(''); } );
}, 'itemType.remove(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.toggle(''); } );
}, 'itemType.toggle(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.contains('a b'); } );
}, 'itemType.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.add('a b'); } );
}, 'itemType.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.remove('a b'); } );
}, 'itemType.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.toggle('a b'); } );
}, 'itemType.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
var testEl = makeEl('div',{itemtype:'foo'});
assert_true( testEl.itemType.contains('foo'), 'before change' );
testEl.setAttribute('itemtype','bar');
assert_true( testEl.itemType.contains('bar'), 'after change' );
assert_false( testEl.itemType.contains('foo'), 'after change' );
}, 'itemType.contains must update when the underlying attribute is changed');
test(function () {
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('FOO') );
}, 'itemType.contains must be case sensitive');
test(function () {
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo.') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo)') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo\'') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo$') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo~') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo?') );
assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo\\') );
}, 'itemType.contains must not match when punctuation characters are added');
test(function () {
var elem = makeEl('div',{itemtype:'foo'});
elem.itemType.add('FOO');
assert_true( elem.itemType.contains('foo') );
}, 'itemType.add must not remove existing tokens');
test(function () {
assert_true( makeEl('div',{itemtype:'foo FOO'}).itemType.contains('FOO') );
}, 'itemType.contains case sensitivity must match a case-specific string');
test(function () {
assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType.length, 2 );
}, 'itemType.length must correctly reflect the number of tokens');
test(function () {
assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType.item(0), 'foo' );
}, 'itemType.item(0) must return the first token');
test(function () {
var elem = makeEl('div',{itemtype:'foo'});
elem.itemType.add('FOO');
assert_equals( elem.itemType.item(1), 'FOO' );
}, 'itemType.item must return case-sensitive strings and preserve token order');
test(function () {
assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[0], 'foo' );
}, 'itemType[0] must return the first token');
test(function () {
assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[1], 'FOO' );
}, 'itemType[index] must return case-sensitive strings and preserve token order');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[2], window.undefined );
}, 'itemType[index] must still be undefined for out-of-range index when earlier indexes exist');
test(function () {
var elem = makeEl('div',{});
elem.itemType.add('foo');
elem.itemType.add('FOO');
assert_equals( elem.getAttribute('itemtype'), 'foo FOO' );
}, 'itemtype attribute must update correctly when items have been added through itemType');
test(function () {
var elem = makeEl('div',{});
elem.itemType.add('foo');
elem.itemType.add('FOO');
assert_equals( elem.itemType + '', 'foo FOO' );
}, 'itemType must stringify correctly when items have been added');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.add('foo');
assert_equals( elem.itemType.length, 2 );
assert_equals( elem.itemType + '', 'foo FOO' );
}, 'itemType.add must not make any changes if an existing token is added');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.remove('bar');
assert_equals( elem.itemType.length, 2 );
assert_equals( elem.itemType + '', 'foo FOO' );
}, 'itemType.remove must not make any changes if a non-existing token is removed');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.remove('foo');
assert_equals( elem.itemType.length, 1 );
assert_equals( elem.itemType.toString(), 'FOO' );
assert_false( elem.itemType.contains('foo') );
assert_true( elem.itemType.contains('FOO') );
}, 'itemType.remove must remove existing tokens');
test(function () {
var elem = makeEl('div',{itemtype:'test test'});
elem.itemType.remove('test');
assert_equals( elem.itemType.length, 0 );
assert_false( elem.itemType.contains('test') );
}, 'itemType.remove must remove duplicated tokens');
test(function () {
var elem = makeEl('div',{itemtype:'token1 token2 token3'});
elem.itemType.remove('token2');
assert_equals( elem.itemType.toString(), 'token1 token3' );
}, 'itemType.remove must collapse whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemtype:' token1 token2 '});
elem.itemType.remove('token2');
assert_equals( elem.itemType.toString(), ' token1' );
}, 'itemType.remove must only remove whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemtype:' token1 token2 token1 '});
elem.itemType.remove('token2');
assert_equals( elem.itemType.toString(), ' token1 token1 ' );
}, 'itemType.remove must collapse multiple whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemtype:' token1 token2 token1 '});
elem.itemType.remove('token1');
assert_equals( elem.itemType.toString(), 'token2' );
}, 'itemType.remove must collapse whitespace when removing multiple tokens');
test(function () {
var elem = makeEl('div',{itemtype:' token1 token1 '});
elem.itemType.add('token1');
assert_equals( elem.itemType.toString(), ' token1 token1 ' );
}, 'itemType.add must not affect whitespace when the token already exists');
test(function () {
var elem = makeEl('div',{itemtype:'FOO'});
assert_true(elem.itemType.toggle('foo'));
assert_equals( elem.itemType.length, 2 );
assert_true( elem.itemType.contains('foo') );
assert_true( elem.itemType.contains('FOO') );
}, 'itemType.toggle must toggle tokens case-sensitively when adding');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
assert_false(elem.itemType.toggle('foo'));
assert_false(elem.itemType.toggle('FOO'));
assert_false( elem.itemType.contains('foo') );
assert_false( elem.itemType.contains('FOO') );
}, 'itemType.toggle must be able to remove tokens case-sensitively');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.toggle('foo');
elem.itemType.toggle('FOO');
assert_equals( elem.getAttribute('itemtype'), '' );
}, 'itemtype attribute must be empty when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.toggle('foo');
elem.itemType.toggle('FOO');
assert_equals( elem.itemType.toString(), '' );
}, 'itemType must stringify to an empty string when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.toggle('foo');
elem.itemType.toggle('FOO');
assert_equals( elem.itemType.item(0), null );
}, 'itemType.item(0) must return null when all classes have been removed');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
var elem = makeEl('div',{itemtype:'foo FOO'});
elem.itemType.toggle('foo');
elem.itemType.toggle('FOO');
assert_equals( elem.itemType[0], window.undefined );
}, 'itemType[0] must be undefined when all classes have been removed');
//if the last character of DOMTokenSting underlying character is not a space character, append U+0020", where "space character" is from " \t\r\n\f"
test(function () {
var elem = makeEl('div',{itemtype:'a '});
elem.itemType.add('b');
assert_equals(elem.itemType.toString(),'a b');
}, 'itemType.add should treat " " as a space');
test(function () {
var elem = makeEl('div',{itemtype:'a\t'});
elem.itemType.add('b');
assert_equals(elem.itemType.toString(),'a\tb');
}, 'itemType.add should treat \\t as a space');
test(function () {
var elem = makeEl('div',{itemtype:'a\r'});
elem.itemType.add('b');
assert_equals(elem.itemType.toString(),'a\rb');
}, 'itemType.add should treat \\r as a space');
test(function () {
var elem = makeEl('div',{itemtype:'a\n'});
elem.itemType.add('b');
assert_equals(elem.itemType.toString(),'a\nb');
}, 'itemType.add should treat \\n as a space');
test(function () {
var elem = makeEl('div',{itemtype:'a\f'});
elem.itemType.add('b');
assert_equals(elem.itemType.toString(),'a\fb');
}, 'itemType.add should treat \\f as a space');
test(function () {
var elem = makeEl('div',{itemtype:'foo'});
elem.itemType.remove('foo');
elem.removeAttribute('itemtype');
assert_true( elem.itemType.toggle('foo') );
}, 'itemType.toggle must work after removing the itemtype attribute');
test(function () {
//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
//ES5 makes [[Put]] fail but not throw
var failed = false;
var elem = makeEl('div',{itemtype:'token1'});
try {
elem.itemType.length = 0;
} catch(e) {
failed = e;
}
assert_equals(elem.itemType.length,1);
assert_false(failed,'an error was thrown');
}, 'itemType.length must be read-only');
test(function () {
var failed = false, elem = makeEl('div',{itemtype:'test'}), realList = elem.itemType;
try {
elem.itemType = 'dummy';
} catch(e) {
failed = e;
}
assert_equals(elem.itemType,realList);
assert_equals(elem.itemType.toString(),'dummy','attempting to write should modify the underlying string');
assert_false(failed,'an error was thrown');
}, 'itemType must be read-only');
/* itemProp property tests (properties collection tests are done later) */
test(function () {
assert_equals(makeEl('div',{}).itemProp.toString(),'','no attribute');
assert_equals(makeEl('div',{itemprop:' http://example.com/foo#bar test '}).itemProp.toString(),' http://example.com/foo#bar test ','with URL and simple tokens');
var testEl = makeEl('div',{itemprop:'http://example.com/foo#bar'});
testEl.removeAttribute('itemprop');
assert_equals(testEl.itemProp.toString(),'','removed attribute');
}, 'the itemprop attribute must be reflected by the .itemProp property');
test(function () {
assert_equals( typeof makeEl('div',{}).itemProp, 'object' );
}, 'the itemProp property must be an object');
test(function () {
assert_true( makeEl('div',{}).itemProp instanceof DOMTokenList, 'instanceof test' );
DOMTokenList.prototype.customProperty = true;
assert_true( makeEl('div',{}).itemProp.customProperty, 'inheritance test' );
}, 'the itemProp property must implement DOMTokenList');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.itemProp, testEl.itemProp );
}, 'the itemProp property must always reference the same object');
test(function () {
assert_equals( makeEl('div',{itemprop:'test test'}).itemProp.length, 2, 'duplicates in initial string should be preserved' );
assert_equals( makeEl('div',{itemprop:'test test'}).itemProp.item(0), 'test' );
assert_true( makeEl('div',{itemprop:'test test'}).itemProp.contains('test') );
}, 'itemProp must be correct for an element that has itemprop tokens');
test(function () {
assert_equals( makeEl('div',{itemprop:' '}).itemProp.length, 0 );
}, 'itemProp.length must be 0 for an element that has no tokens');
test(function () {
assert_false( makeEl('div',{itemprop:' '}).itemProp.contains('foo') );
}, 'itemProp must not contain an undefined class');
test(function () {
assert_equals( makeEl('div',{itemprop:' '}).itemProp.item(0), null );
}, 'itemProp.item() must return null for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemprop:' '}).itemProp.item(-1), null );
}, 'itemProp.item() must return null for negative index');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemprop:' '}).itemProp[0], window.undefined );
}, 'itemProp[index] must be undefined for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemprop:' '}).itemProp[-1], window.undefined );
}, 'itemProp[index] must be undefined for negative index');
test(function () {
assert_equals( makeEl('div',{itemprop:' '}).itemProp.toString(), ' ' );
}, 'empty itemProp should stringify to contain the attribute\'s whitespace');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.contains(''); } );
}, 'itemProp.contains(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.add(''); } );
}, 'itemProp.add(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.remove(''); } );
}, 'itemProp.remove(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.toggle(''); } );
}, 'itemProp.toggle(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.contains('a b'); } );
}, '.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.add('a b'); } );
}, 'itemProp.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.remove('a b'); } );
}, 'itemProp.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.toggle('a b'); } );
}, 'itemProp.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
var testEl = makeEl('div',{itemprop:'foo'});
assert_true( testEl.itemProp.contains('foo'), 'before change' );
testEl.setAttribute('itemprop','bar');
assert_true( testEl.itemProp.contains('bar'), 'after change' );
assert_false( testEl.itemProp.contains('foo'), 'after change' );
}, 'itemProp.contains must update when the underlying attribute is changed');
test(function () {
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('FOO') );
}, 'itemProp.contains must be case sensitive');
test(function () {
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo.') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo)') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo\'') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo$') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo~') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo?') );
assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo\\') );
}, 'itemProp.contains must not match when punctuation characters are added');
test(function () {
var elem = makeEl('div',{itemprop:'foo'});
elem.itemProp.add('FOO');
assert_true( elem.itemProp.contains('foo') );
}, 'itemProp.add must not remove existing tokens');
test(function () {
assert_true( makeEl('div',{itemprop:'foo FOO'}).itemProp.contains('FOO') );
}, 'itemProp.contains case sensitivity must match a case-specific string');
test(function () {
assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp.length, 2 );
}, 'itemProp.length must correctly reflect the number of tokens');
test(function () {
assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp.item(0), 'foo' );
}, 'itemProp.item(0) must return the first token');
test(function () {
var elem = makeEl('div',{itemprop:'foo'});
elem.itemProp.add('FOO');
assert_equals( elem.itemProp.item(1), 'FOO' );
}, 'itemProp.item must return case-sensitive strings and preserve token order');
test(function () {
assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[0], 'foo' );
}, 'itemProp[0] must return the first token');
test(function () {
assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[1], 'FOO' );
}, 'itemProp[index] must return case-sensitive strings and preserve token order');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[2], window.undefined );
}, 'itemProp[index] must still be undefined for out-of-range index when earlier indexes exist');
test(function () {
var elem = makeEl('div',{});
elem.itemProp.add('foo');
elem.itemProp.add('FOO');
assert_equals( elem.getAttribute('itemprop'), 'foo FOO' );
}, 'itemprop attribute must update correctly when items have been added through itemProp');
test(function () {
var elem = makeEl('div',{});
elem.itemProp.add('foo');
elem.itemProp.add('FOO');
assert_equals( elem.itemProp + '', 'foo FOO' );
}, 'itemProp must stringify correctly when items have been added');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.add('foo');
assert_equals( elem.itemProp.length, 2 );
assert_equals( elem.itemProp + '', 'foo FOO' );
}, 'itemProp.add must not make any changes if an existing token is added');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.remove('bar');
assert_equals( elem.itemProp.length, 2 );
assert_equals( elem.itemProp + '', 'foo FOO' );
}, 'itemProp.remove must not make any changes if a non-existing token is removed');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.remove('foo');
assert_equals( elem.itemProp.length, 1 );
assert_equals( elem.itemProp.toString(), 'FOO' );
assert_false( elem.itemProp.contains('foo') );
assert_true( elem.itemProp.contains('FOO') );
}, 'itemProp.remove must remove existing tokens');
test(function () {
var elem = makeEl('div',{itemprop:'test test'});
elem.itemProp.remove('test');
assert_equals( elem.itemProp.length, 0 );
assert_false( elem.itemProp.contains('test') );
}, 'itemProp.remove must remove duplicated tokens');
test(function () {
var elem = makeEl('div',{itemprop:'token1 token2 token3'});
elem.itemProp.remove('token2');
assert_equals( elem.itemProp.toString(), 'token1 token3' );
}, 'itemProp.remove must collapse whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemprop:' token1 token2 '});
elem.itemProp.remove('token2');
assert_equals( elem.itemProp.toString(), ' token1' );
}, 'itemProp.remove must only remove whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemprop:' token1 token2 token1 '});
elem.itemProp.remove('token2');
assert_equals( elem.itemProp.toString(), ' token1 token1 ' );
}, 'itemProp.remove must collapse multiple whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemprop:' token1 token2 token1 '});
elem.itemProp.remove('token1');
assert_equals( elem.itemProp.toString(), 'token2' );
}, 'itemProp.remove must collapse whitespace when removing multiple tokens');
test(function () {
var elem = makeEl('div',{itemprop:' token1 token1 '});
elem.itemProp.add('token1');
assert_equals( elem.itemProp.toString(), ' token1 token1 ' );
}, 'itemProp.add must not affect whitespace when the token already exists');
test(function () {
var elem = makeEl('div',{itemprop:'FOO'});
assert_true(elem.itemProp.toggle('foo'));
assert_equals( elem.itemProp.length, 2 );
assert_true( elem.itemProp.contains('foo') );
assert_true( elem.itemProp.contains('FOO') );
}, 'itemProp.toggle must toggle tokens case-sensitively when adding');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
assert_false(elem.itemProp.toggle('foo'));
assert_false(elem.itemProp.toggle('FOO'));
assert_false( elem.itemProp.contains('foo') );
assert_false( elem.itemProp.contains('FOO') );
}, 'itemProp.toggle must be able to remove tokens case-sensitively');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.toggle('foo');
elem.itemProp.toggle('FOO');
assert_equals( elem.getAttribute('itemprop'), '' );
}, 'itemprop attribute must be empty when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.toggle('foo');
elem.itemProp.toggle('FOO');
assert_equals( elem.itemProp.toString(), '' );
}, 'itemProp must stringify to an empty string when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.toggle('foo');
elem.itemProp.toggle('FOO');
assert_equals( elem.itemProp.item(0), null );
}, 'itemProp.item(0) must return null when all classes have been removed');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
var elem = makeEl('div',{itemprop:'foo FOO'});
elem.itemProp.toggle('foo');
elem.itemProp.toggle('FOO');
assert_equals( elem.itemProp[0], window.undefined );
}, 'itemProp[0] must be undefined when all classes have been removed');
//if the last character of DOMTokenSting underlying character is not a space character, append U+0020", where "space character" is from " \t\r\n\f"
test(function () {
var elem = makeEl('div',{itemprop:'a '});
elem.itemProp.add('b');
assert_equals(elem.itemProp.toString(),'a b');
}, 'itemProp.add should treat " " as a space');
test(function () {
var elem = makeEl('div',{itemprop:'a\t'});
elem.itemProp.add('b');
assert_equals(elem.itemProp.toString(),'a\tb');
}, 'itemProp.add should treat \\t as a space');
test(function () {
var elem = makeEl('div',{itemprop:'a\r'});
elem.itemProp.add('b');
assert_equals(elem.itemProp.toString(),'a\rb');
}, 'itemProp.add should treat \\r as a space');
test(function () {
var elem = makeEl('div',{itemprop:'a\n'});
elem.itemProp.add('b');
assert_equals(elem.itemProp.toString(),'a\nb');
}, 'itemProp.add should treat \\n as a space');
test(function () {
var elem = makeEl('div',{itemprop:'a\f'});
elem.itemProp.add('b');
assert_equals(elem.itemProp.toString(),'a\fb');
}, 'itemProp.add should treat \\f as a space');
test(function () {
var elem = makeEl('div',{itemprop:'foo'});
elem.itemProp.remove('foo');
elem.removeAttribute('itemprop');
assert_true( elem.itemProp.toggle('foo') );
}, 'itemProp.toggle must work after removing the itemprop attribute');
test(function () {
//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
//ES5 makes [[Put]] fail but not throw
var failed = false;
var elem = makeEl('div',{itemprop:'token1'});
try {
elem.itemProp.length = 0;
} catch(e) {
failed = e;
}
assert_equals(elem.itemProp.length,1);
assert_false(failed,'an error was thrown');
}, 'itemProp.length must be read-only');
test(function () {
var failed = false, elem = makeEl('div',{itemprop:'test'}), realList = elem.itemProp;
try {
elem.itemProp = 'dummy';
} catch(e) {
failed = e;
}
assert_equals(elem.itemProp,realList);
assert_equals(elem.itemProp.toString(),'dummy','attempting to write should modify the underlying string');
assert_false(failed,'an error was thrown');
}, 'itemProp must be read-only');
/* itemId property tests */
test(function () {
assert_equals( makeEl('div',{itemid:'http://example.com/foo'}).itemId, 'http://example.com/foo' );
assert_equals( makeEl('div',{itemid:'http://example.com/FOO'}).itemId, 'http://example.com/FOO', 'case-sensitive' );
assert_equals( makeEl('div',{itemid:' http://example.com/foo '}).itemId, 'http://example.com/foo', 'whitespace' );
assert_equals( makeEl('div',{itemid:'data:text/plain,'}).itemId, 'data:text/plain,' );
assert_equals( makeEl('div',{itemid:'madeup:onthespot'}).itemId, 'madeup:onthespot' );
assert_equals( makeEl('div',{}).itemId, '' );
}, 'the itemid attribute must be reflected by the .itemId property');
test(function () {
var testEl = makeEl('div',{});
testEl.itemId = 'http://example.com/foo';
assert_equals(testEl.itemId,'http://example.com/foo','writing a URL');
testEl.itemId = '';
assert_equals(testEl.itemId,location.href,'writing an empty string');
}, 'the itemId property must be read/write');
test(function () {
var testEl = makeEl('div',{});
testEl.itemId = 'http://example.com/foo';
assert_true(testEl.hasAttribute('itemid'),'writing a URL');
assert_equals(testEl.getAttribute('itemid'),'http://example.com/foo','writing a URL');
testEl = makeEl('div',{})
testEl.itemId = '';
assert_true(testEl.hasAttribute('itemid'),'writing an empty string');
assert_equals(testEl.getAttribute('itemid'),'','writing an empty string');
}, 'writing to the itemId property must create the itemid content attribute');
test(function () {
assert_equals( makeEl('div',{itemid:'foo'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo'),'foo' );
assert_equals( makeEl('div',{itemid:'foo bar'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo%20bar'),'foo bar' );
assert_equals( makeEl('div',{itemid:'foo\u0129 bar'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo%C4%A9%20bar'),'foo\u0129 bar' );
}, 'the itemId property must see the resolved itemid URL');
test(function () {
var testEl = makeEl('div',{});
testEl.itemId = 'foo';
assert_equals( testEl.itemId, location.href.replace(/\/[^\/]*$/,'\/foo') );
}, 'the itemId property must see the resolved itemId property URL on setting');
test(function () {
var testEl = makeEl('div',{});
testEl.itemId = 'foo';
assert_equals( testEl.getAttribute('itemid'), 'foo' );
}, 'the itemid attribute must see the resolved itemId URL');
/* itemRef property tests (properties collection tests are done later) */
test(function () {
assert_equals(makeEl('div',{}).itemRef.toString(),'','no attribute');
assert_equals(makeEl('div',{itemref:' foo bar '}).itemRef.toString(),' foo bar ','with simple tokens');
var testEl = makeEl('div',{itemref:'foo'});
testEl.removeAttribute('itemref');
assert_equals(testEl.itemRef.toString(),'','removed attribute');
}, 'the itemref attribute must be reflected by the .itemRef property');
test(function () {
assert_equals( typeof makeEl('div',{}).itemRef, 'object' );
}, 'the itemRef property must be an object');
test(function () {
assert_true( makeEl('div',{}).itemRef instanceof DOMTokenList, 'instanceof test' );
DOMTokenList.prototype.customProperty = true;
assert_true( makeEl('div',{}).itemRef.customProperty, 'inheritance test' );
}, 'the itemRef property must implement DOMTokenList');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.itemRef, testEl.itemRef );
}, 'the itemRef property must always reference the same object');
test(function () {
assert_equals( makeEl('div',{itemref:'test test'}).itemRef.length, 2, 'duplicates in initial string should be preserved' );
assert_equals( makeEl('div',{itemref:'test test'}).itemRef.item(0), 'test' );
assert_true( makeEl('div',{itemref:'test test'}).itemRef.contains('test') );
}, 'itemRef must be correct for an element that has itemref tokens');
test(function () {
assert_equals( makeEl('div',{itemref:' '}).itemRef.length, 0 );
}, 'itemRef.length must be 0 for an element that has no tokens');
test(function () {
assert_false( makeEl('div',{itemref:' '}).itemRef.contains('foo') );
}, 'itemRef must not contain an undefined class');
test(function () {
assert_equals( makeEl('div',{itemref:' '}).itemRef.item(0), null );
}, 'itemRef.item() must return null for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemref:' '}).itemRef.item(-1), null );
}, 'itemRef.item() must return null for negative index');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemref:' '}).itemRef[0], window.undefined );
}, 'itemRef[index] must be undefined for out-of-range index');
test(function () {
assert_equals( makeEl('div',{itemref:' '}).itemRef[-1], window.undefined );
}, 'itemRef[index] must be undefined for negative index');
test(function () {
assert_equals( makeEl('div',{itemref:' '}).itemRef.toString(), ' ' );
}, 'empty itemRef should stringify to contain the attribute\'s whitespace');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.contains(''); } );
}, 'itemRef.contains(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.add(''); } );
}, 'itemRef.add(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.remove(''); } );
}, 'itemRef.remove(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.toggle(''); } );
}, 'itemRef.toggle(empty_string) must throw a SYNTAX_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.contains('a b'); } );
}, 'itemRef.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.add('a b'); } );
}, 'itemRef.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.remove('a b'); } );
}, 'itemRef.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.toggle('a b'); } );
}, 'itemRef.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
test(function () {
var testEl = makeEl('div',{itemref:'foo'});
assert_true( testEl.itemRef.contains('foo'), 'before change' );
testEl.setAttribute('itemref','bar');
assert_true( testEl.itemRef.contains('bar'), 'after change' );
assert_false( testEl.itemRef.contains('foo'), 'after change' );
}, 'itemRef.contains must update when the underlying attribute is changed');
test(function () {
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('FOO') );
}, 'itemRef.contains must be case sensitive');
test(function () {
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo.') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo)') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo\'') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo$') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo~') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo?') );
assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo\\') );
}, 'itemRef.contains must not match when punctuation characters are added');
test(function () {
var elem = makeEl('div',{itemref:'foo'});
elem.itemRef.add('FOO');
assert_true( elem.itemRef.contains('foo') );
}, 'itemRef.add must not remove existing tokens');
test(function () {
assert_true( makeEl('div',{itemref:'foo FOO'}).itemRef.contains('FOO') );
}, 'itemRef.contains case sensitivity must match a case-specific string');
test(function () {
assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef.length, 2 );
}, 'itemRef.length must correctly reflect the number of tokens');
test(function () {
assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef.item(0), 'foo' );
}, 'itemRef.item(0) must return the first token');
test(function () {
var elem = makeEl('div',{itemref:'foo'});
elem.itemRef.add('FOO');
assert_equals( elem.itemRef.item(1), 'FOO' );
}, 'itemRef.item must return case-sensitive strings and preserve token order');
test(function () {
assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[0], 'foo' );
}, 'itemRef[0] must return the first token');
test(function () {
assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[1], 'FOO' );
}, 'itemRef[index] must return case-sensitive strings and preserve token order');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[2], window.undefined );
}, 'itemRef[index] must still be undefined for out-of-range index when earlier indexes exist');
test(function () {
var elem = makeEl('div',{});
elem.itemRef.add('foo');
elem.itemRef.add('FOO');
assert_equals( elem.getAttribute('itemref'), 'foo FOO' );
}, 'itemref attribute must update correctly when items have been added through itemRef');
test(function () {
var elem = makeEl('div',{});
elem.itemRef.add('foo');
elem.itemRef.add('FOO');
assert_equals( elem.itemRef + '', 'foo FOO' );
}, 'itemRef must stringify correctly when items have been added');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.add('foo');
assert_equals( elem.itemRef.length, 2 );
assert_equals( elem.itemRef + '', 'foo FOO' );
}, 'itemRef.add must not make any changes if an existing token is added');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.remove('bar');
assert_equals( elem.itemRef.length, 2 );
assert_equals( elem.itemRef + '', 'foo FOO' );
}, 'itemRef.remove must not make any changes if a non-existing token is removed');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.remove('foo');
assert_equals( elem.itemRef.length, 1 );
assert_equals( elem.itemRef.toString(), 'FOO' );
assert_false( elem.itemRef.contains('foo') );
assert_true( elem.itemRef.contains('FOO') );
}, 'itemRef.remove must remove existing tokens');
test(function () {
var elem = makeEl('div',{itemref:'test test'});
elem.itemRef.remove('test');
assert_equals( elem.itemRef.length, 0 );
assert_false( elem.itemRef.contains('test') );
}, 'itemRef.remove must remove duplicated tokens');
test(function () {
var elem = makeEl('div',{itemref:'token1 token2 token3'});
elem.itemRef.remove('token2');
assert_equals( elem.itemRef.toString(), 'token1 token3' );
}, 'itemRef.remove must collapse whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemref:' token1 token2 '});
elem.itemRef.remove('token2');
assert_equals( elem.itemRef.toString(), ' token1' );
}, 'itemRef.remove must only remove whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemref:' token1 token2 token1 '});
elem.itemRef.remove('token2');
assert_equals( elem.itemRef.toString(), ' token1 token1 ' );
}, 'itemRef.remove must collapse multiple whitespace around removed tokens');
test(function () {
var elem = makeEl('div',{itemref:' token1 token2 token1 '});
elem.itemRef.remove('token1');
assert_equals( elem.itemRef.toString(), 'token2' );
}, 'itemRef.remove must collapse whitespace when removing multiple tokens');
test(function () {
var elem = makeEl('div',{itemref:' token1 token1 '});
elem.itemRef.add('token1');
assert_equals( elem.itemRef.toString(), ' token1 token1 ' );
}, 'itemRef.add must not affect whitespace when the token already exists');
test(function () {
var elem = makeEl('div',{itemref:'FOO'});
assert_true(elem.itemRef.toggle('foo'));
assert_equals( elem.itemRef.length, 2 );
assert_true( elem.itemRef.contains('foo') );
assert_true( elem.itemRef.contains('FOO') );
}, 'itemRef.toggle must toggle tokens case-sensitively when adding');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
assert_false(elem.itemRef.toggle('foo'));
assert_false(elem.itemRef.toggle('FOO'));
assert_false( elem.itemRef.contains('foo') );
assert_false( elem.itemRef.contains('FOO') );
}, 'itemRef.toggle must be able to remove tokens case-sensitively');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.toggle('foo');
elem.itemRef.toggle('FOO');
assert_equals( elem.getAttribute('itemref'), '' );
}, 'itemref attribute must be empty when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.toggle('foo');
elem.itemRef.toggle('FOO');
assert_equals( elem.itemRef.toString(), '' );
}, 'itemRef must stringify to an empty string when all classes have been removed');
test(function () {
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.toggle('foo');
elem.itemRef.toggle('FOO');
assert_equals( elem.itemRef.item(0), null );
}, 'itemRef.item(0) must return null when all classes have been removed');
test(function () {
/* the normative part of the spec states that:
"unless the length is zero, in which case there are no supported property indices"
...
"The term[...] supported property indices [is] used as defined in the WebIDL specification."
WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
var elem = makeEl('div',{itemref:'foo FOO'});
elem.itemRef.toggle('foo');
elem.itemRef.toggle('FOO');
assert_equals( elem.itemRef[0], window.undefined );
}, 'itemRef[0] must be undefined when all classes have been removed');
//if the last character of DOMTokenSting underlying character is not a space character, append U+0020", where "space character" is from " \t\r\n\f"
test(function () {
var elem = makeEl('div',{itemref:'a '});
elem.itemRef.add('b');
assert_equals(elem.itemRef.toString(),'a b');
}, 'itemRef.add should treat " " as a space');
test(function () {
var elem = makeEl('div',{itemref:'a\t'});
elem.itemRef.add('b');
assert_equals(elem.itemRef.toString(),'a\tb');
}, 'itemRef.add should treat \\t as a space');
test(function () {
var elem = makeEl('div',{itemref:'a\r'});
elem.itemRef.add('b');
assert_equals(elem.itemRef.toString(),'a\rb');
}, 'itemRef.add should treat \\r as a space');
test(function () {
var elem = makeEl('div',{itemref:'a\n'});
elem.itemRef.add('b');
assert_equals(elem.itemRef.toString(),'a\nb');
}, 'itemRef.add should treat \\n as a space');
test(function () {
var elem = makeEl('div',{itemref:'a\f'});
elem.itemRef.add('b');
assert_equals(elem.itemRef.toString(),'a\fb');
}, 'itemRef.add should treat \\f as a space');
test(function () {
var elem = makeEl('div',{itemref:'foo'});
elem.itemRef.remove('foo');
elem.removeAttribute('itemref');
assert_true( elem.itemRef.toggle('foo') );
}, 'itemRef.toggle must work after removing the itemref attribute');
test(function () {
//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
//ES5 makes [[Put]] fail but not throw
var failed = false;
var elem = makeEl('div',{itemref:'token1'});
try {
elem.itemRef.length = 0;
} catch(e) {
failed = e;
}
assert_equals(elem.itemRef.length,1);
assert_false(failed,'an error was thrown');
}, 'itemRef.length must be read-only');
test(function () {
var failed = false, elem = makeEl('div',{itemref:'test'}), realList = elem.itemRef;
try {
elem.itemRef = 'dummy';
} catch(e) {
failed = e;
}
assert_equals(elem.itemRef,realList);
assert_equals(elem.itemRef.toString(),'dummy','attempting to write should modify the underlying string');
assert_false(failed,'an error was thrown');
}, 'itemRef must be read-only');
/* itemValue property tests */
test(function () {
assert_equals( makeEl('meta',{content:'test'}).itemValue, null, 'meta' );
assert_equals( makeEl('audio',{src:'test'}).itemValue, null, 'audio' );
assert_equals( makeEl('embed',{src:'test'}).itemValue, null, 'embed' );
assert_equals( makeEl('iframe',{src:'test'}).itemValue, null, 'iframe' );
assert_equals( makeEl('img',{src:'test'}).itemValue, null, 'img' );
assert_equals( makeEl('source',{src:'test'}).itemValue, null, 'source' );
assert_equals( makeEl('track',{src:'test'}).itemValue, null, 'track' );
assert_equals( makeEl('video',{src:'test'}).itemValue, null, 'video' );
assert_equals( makeEl('a',{href:'test'}).itemValue, null, 'a' );
assert_equals( makeEl('area',{href:'test'}).itemValue, null, 'area' );
assert_equals( makeEl('link',{href:'test'}).itemValue, null, 'link' );
assert_equals( makeEl('object',{data:'test'}).itemValue, null, 'object' );
assert_equals( makeEl('time',{}).itemValue, null, 'time without datetime' );
assert_equals( makeEl('time',{datetime:'test'}).itemValue, null, 'time with datetime' );
assert_equals( makeEl('div',{},'test').itemValue, null, 'otherwise' );
assert_equals( makeEl('madeuponthespot',{},'test').itemValue, null, 'unknown element' );
}, 'itemValue must be null if the element does not have an itemprop attribute');
test(function () {
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('meta',{content:'test'}); testEl.itemValue = 'test2'; }, 'meta' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('audio',{content:'test'}); testEl.itemValue = 'test2'; }, 'audio' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('embed',{content:'test'}); testEl.itemValue = 'test2'; }, 'embed' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('iframe',{content:'test'}); testEl.itemValue = 'test2'; }, 'iframe' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('img',{content:'test'}); testEl.itemValue = 'test2'; }, 'img' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('source',{content:'test'}); testEl.itemValue = 'test2'; }, 'source' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('track',{content:'test'}); testEl.itemValue = 'test2'; }, 'track' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('video',{content:'test'}); testEl.itemValue = 'test2'; }, 'video' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('a',{href:'test'}); testEl.itemValue = 'test2'; }, 'a' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('area',{href:'test'}); testEl.itemValue = 'test2'; }, 'area' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('link',{href:'test'}); testEl.itemValue = 'test2'; }, 'link' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('object',{data:'test'}); testEl.itemValue = 'test2'; }, 'object' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('time',{}); testEl.itemValue = 'test2'; }, 'time without datetime' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('time',{datetime:'test'}); testEl.itemValue = 'test2'; }, 'time with datetime' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('div',{},'test'); testEl.itemValue = 'test2'; }, 'otherwise' );
assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('madeuponthespot',{},'test'); testEl.itemValue = 'test2'; }, 'unknown element' );
}, 'writing to itemValue must throw an INVALID_ACCESS_ERR error if the element does not have an itemprop attribute');
test(function () {
var testEl;
testEl = makeEl('meta',{itemscope:'itemscope',itemprop:'foo',content:'test'});
assert_equals( testEl.itemValue, testEl, 'meta' );
testEl = makeEl('audio',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'audio' );
testEl = makeEl('embed',{itemscope:'itemscope',itemprop:'foo',src:'test'});
assert_equals( testEl.itemValue, testEl, 'embed' );
testEl = makeEl('iframe',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'iframe' );
testEl = makeEl('img',{itemscope:'itemscope',itemprop:'foo',src:'test'});
assert_equals( testEl.itemValue, testEl, 'img' );
testEl = makeEl('source',{itemscope:'itemscope',itemprop:'foo',src:'test'});
assert_equals( testEl.itemValue, testEl, 'source' );
testEl = makeEl('track',{itemscope:'itemscope',itemprop:'foo',src:'test'});
assert_equals( testEl.itemValue, testEl, 'track' );
testEl = makeEl('video',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'video' );
testEl = makeEl('a',{itemscope:'itemscope',itemprop:'foo',href:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'a' );
testEl = makeEl('area',{itemscope:'itemscope',itemprop:'foo',href:'test'});
assert_equals( testEl.itemValue, testEl, 'area' );
testEl = makeEl('link',{itemscope:'itemscope',itemprop:'foo',href:'test'});
assert_equals( testEl.itemValue, testEl, 'link' );
testEl = makeEl('object',{itemscope:'itemscope',itemprop:'foo',data:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'object' );
testEl = makeEl('time',{itemscope:'itemscope',itemprop:'foo'},'fail');
assert_equals( testEl.itemValue, testEl, 'time without datetime' );
testEl = makeEl('time',{itemscope:'itemscope',itemprop:'foo',datetime:'test'},'fail');
assert_equals( testEl.itemValue, testEl, 'time with datetime' );
testEl = makeEl('div',{itemscope:'itemscope',itemprop:'foo'},'test');
assert_equals( testEl.itemValue, testEl, 'otherwise' );
testEl = makeEl('madeuponthespot',{itemscope:'itemscope',itemprop:'foo'},'test');
assert_equals( testEl.itemValue, testEl, 'unknown element' );
testEl = makeEl('madeuponthespot',{itemscope:'itemscope',itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test');
assert_equals( testEl.itemValue, testEl, 'unknown element with known attributes' );
testEl = makeEl('input',{itemscope:'itemscope',itemprop:'foo',value:'test'},'test');
assert_equals( testEl.itemValue, testEl, 'input' );
}, 'itemValue must return the element if the element has an itemscope attribute');
test(function () {
var testEl = makeEl('meta',{itemprop:'foo',content:'test'});
assert_equals( testEl.itemValue, 'test', 'reading' );
testEl.content = 'retest';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = 'bar';
assert_equals( testEl.content, 'bar', 'writing (checking content)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
}, 'itemValue must reflect the content attribute on meta elements');
test(function () {
var testEl = makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text');
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
assert_equals( makeEl('audio',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on audio elements');
test(function () {
var testEl = makeEl('embed',{itemprop:'foo',src:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on embed elements');
test(function () {
var testEl = makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text');
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
assert_equals( makeEl('iframe',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on iframe elements');
test(function () {
var testEl = makeEl('img',{itemprop:'foo',src:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on img elements');
test(function () {
var testEl = makeEl('source',{itemprop:'foo',src:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on source elements');
test(function () {
var testEl = makeEl('track',{itemprop:'foo',src:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on track elements');
test(function () {
var testEl = makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text');
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.src = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
assert_equals( makeEl('video',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
testEl.src = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on video elements');
test(function () {
var testEl = makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text');
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.href = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
assert_equals( makeEl('a',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
testEl.href = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on anchor elements');
test(function () {
var testEl = makeEl('area',{itemprop:'foo',href:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.href = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.href = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on area elements');
test(function () {
var testEl = makeEl('link',{itemprop:'foo',href:'http://example.org/'});
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.href = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
testEl.href = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on link elements');
test(function () {
var testEl = makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text');
assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
testEl.data = 'http://example.net/';
assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
testEl.itemValue = 'http://example.com/';
assert_equals( testEl.data, 'http://example.com/', 'writing (checking data)' );
assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
assert_equals( makeEl('object',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
testEl.data = 'bar';
assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
}, 'itemValue must reflect the src attribute on object elements');
test(function () {
var testEl = makeEl('time',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
assert_equals( testEl.itemValue, 'te st ing', 'reading' );
testEl.innerHTML = 'retest';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = '2001-02-03T04:05:06Z';
assert_equals( testEl.dateTime, '2001-02-03T04:05:06Z', 'writing (checking dateTime)' );
assert_equals( testEl.textContent, 'retest', 'writing (checking textContent)' );
assert_equals( testEl.itemValue, '2001-02-03T04:05:06Z', 'writing (checking itemValue)' );
}, 'itemValue must reflect the dateTime attribute of time elements with no datetime attribute');
test(function () {
var testEl = makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="bar" itemscope>st</span> ing');
assert_equals( testEl.itemValue, 'test', 'reading' );
testEl.dateTime = 'retest';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = '2001-02-03T04:05:06Z';
assert_equals( testEl.dateTime, '2001-02-03T04:05:06Z', 'writing (checking dateTime)' );
assert_equals( testEl.textContent, 'te st ing', 'writing (checking textContent)' );
}, 'itemValue must reflect the datetime attribute of time elements with a datetime attribute');
test(function () {
var testEl = makeEl('div',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
assert_equals( testEl.itemValue, 'te st ing', 'reading' );
testEl.innerHTML = 're<strong>te</strong>st';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = 'test';
assert_equals( testEl.textContent, 'test', 'writing' );
}, 'itemValue must reflect the textContent of other elements');
test(function () {
var testEl = makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
assert_equals( testEl.itemValue, 'te st ing', 'reading' );
testEl.innerHTML = 're<strong>te</strong>st';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = 'test';
assert_equals( testEl.textContent, 'test', 'writing' );
}, 'itemValue must reflect the textContent of unknown elements');
test(function () {
var testEl = makeEl('madeuponthespot',{itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'te <span itemprop="bar" itemscope>st</span> ing');
assert_equals( testEl.itemValue, 'te st ing', 'reading' );
testEl.innerHTML = 're<strong>te</strong>st';
assert_equals( testEl.itemValue, 'retest', 'reading after change' );
testEl.itemValue = 'test';
assert_equals( testEl.textContent, 'test', 'writing' );
}, 'itemValue must reflect the textContent of unknown elements with known attributes');
test(function () {
var testEl = makeEl('input',{itemprop:'foo',value:'test'});
assert_equals( testEl.itemValue, '', 'reading' );
testEl.value = 'retest';
assert_equals( testEl.itemValue, '', 'reading after change' );
}, 'itemValue must not reflect the value of input elements');
test(function () {
var testEl, eltypes = [
makeEl('meta',{itemprop:'foo',content:'test'}),
makeEl('audio',{itemprop:'foo',src:'test'},'fail'),
makeEl('embed',{itemprop:'foo',src:'test'}),
makeEl('iframe',{itemprop:'foo',src:'test'},'fail'),
makeEl('img',{itemprop:'foo',src:'test'}),
makeEl('source',{itemprop:'foo',src:'test'}),
makeEl('track',{itemprop:'foo',src:'test'}),
makeEl('video',{itemprop:'foo',src:'test'},'fail'),
makeEl('a',{itemprop:'foo',href:'test'},'fail'),
makeEl('area',{itemprop:'foo',href:'test'}),
makeEl('link',{itemprop:'foo',href:'test'}),
makeEl('object',{itemprop:'foo',data:'test'},'fail'),
makeEl('time',{itemprop:'foo'},'fail'),
makeEl('time',{itemprop:'foo',datetime:'test'},'fail'),
makeEl('div',{itemprop:'foo'},'test'),
makeEl('madeuponthespot',{itemprop:'foo'},'test'),
makeEl('madeuponthespot',{itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test'),
makeEl('input',{itemprop:'foo',value:'test'},'test')
], beforeValues, i;
for( i = 0; i < eltypes.length; i++ ) {
testEl = eltypes[i];
beforeValues = testEl.itemValue;
testEl.itemScope = true;
assert_equals( testEl.itemValue, testEl, 'itemscope enabled on '+testEl.tagName+' index '+i );
testEl.itemScope = false;
assert_equals( testEl.itemValue, beforeValues, 'itemscope disabled on '+testEl.tagName+' index '+i );
testEl.itemScope = true;
testEl.removeAttribute('itemscope');
assert_equals( testEl.itemValue, beforeValues, 'itemscope attribute removed on '+testEl.tagName+' index '+i );
}
}, 'dynamic changes of itemscope should change the value exposed through itemValue');
test(function () {
var testEl, eltypes = [
makeEl('meta',{itemprop:'foo',content:'test'}),
makeEl('audio',{itemprop:'foo',src:'test'},'fail'),
makeEl('embed',{itemprop:'foo',src:'test'}),
makeEl('iframe',{itemprop:'foo',src:'test'},'fail'),
makeEl('img',{itemprop:'foo',src:'test'}),
makeEl('source',{itemprop:'foo',src:'test'}),
makeEl('track',{itemprop:'foo',src:'test'}),
makeEl('video',{itemprop:'foo',src:'test'},'fail'),
makeEl('a',{itemprop:'foo',href:'test'},'fail'),
makeEl('area',{itemprop:'foo',href:'test'}),
makeEl('link',{itemprop:'foo',href:'test'}),
makeEl('object',{itemprop:'foo',data:'test'},'fail'),
makeEl('time',{itemprop:'foo'},'fail'),
makeEl('time',{itemprop:'foo',datetime:'test'},'fail'),
makeEl('div',{itemprop:'foo'},'test'),
makeEl('madeuponthespot',{itemprop:'foo'},'test'),
makeEl('madeuponthespot',{itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test'),
makeEl('input',{itemprop:'foo',value:'test'},'test')
], beforeValues, i;
for( i = 0; i < eltypes.length; i++ ) {
testEl = eltypes[i];
beforeValues = testEl.itemValue;
testEl.itemProp.remove('foo');
assert_equals( testEl.itemValue, beforeValues, 'itemprop tokens removed on '+testEl.tagName+' index '+i );
testEl.removeAttribute('itemprop');
assert_equals( testEl.itemValue, null, 'itemprop attribute removed on '+testEl.tagName+' index '+i );
testEl.itemProp.toggle('foo');
assert_equals( testEl.itemValue, beforeValues, 'itemprop tokens added on '+testEl.tagName+' index '+i );
}
}, 'dynamic changes of itemprop should change the value exposed through itemValue');
/* properties */
test(function () {
assert_equals( typeof makeEl('div',{}).properties, 'object' );
}, 'the properties property must be an object');
test(function () {
var testEl = makeEl('div',{});
assert_true( testEl.properties instanceof HTMLPropertiesCollection, 'instanceof HTMLPropertiesCollection' );
assert_true( testEl.properties instanceof HTMLCollection, 'instanceof HTMLCollection' );
HTMLPropertiesCollection.prototype.customProperty = true;
HTMLCollection.prototype.anotherCustomProperty = true;
assert_true( testEl.properties.customProperty, 'inheritance from HTMLPropertiesCollection' );
assert_true( testEl.properties.anotherCustomProperty, 'inheritance from HTMLCollection' );
HTMLPropertiesCollection.prototype.anotherCustomProperty = false;
assert_false( testEl.properties.anotherCustomProperty, 'shadowing by HTMLPropertiesCollection' );
}, 'the properties property must implement HTMLPropertiesCollection and HTMLCollection');
test(function () {
var failed = false, elem = makeEl('div',{itemscope:'itemscope'}), realList = elem.properties;
try {
elem.properties = '';
} catch(e) {
failed = e;
}
assert_equals(elem.properties,realList);
assert_false(failed,'an error was thrown');
}, 'the properties property must be read-only');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.properties, testEl.properties );
}, 'the properties property must always reference the same object');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
assert_equals( testEl.properties.length, 0, 'length' );
assert_true( !testEl.properties.item(0), 'item(0)' );
assert_true( !testEl.properties[0], '[0]' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'namedItem' );
assert_true( !testEl.properties['foo'], '[namedItem]' );
assert_equals( testEl.properties.namedItem('foo').getValues().length, 0, 'namedItem' );
assert_equals( testEl.properties.names.length, 0, 'names' );
}, 'the properties collection must be empty if the element does not have an itemscope property');
test(function() {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
assert_throws( new TypeError(), function() { testEl.properties('foo'); } );
assert_throws( new TypeError(), function() { testEl.properties(0); } );
}, 'the properties collection must not support legacycaller');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
testEl.itemScope = true;
assert_equals( testEl.properties.length, 1, 'length' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'item(0)' );
assert_equals( testEl.properties[0], testEl.firstChild, '[0]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'namedItem' );
assert_equals( testEl.properties['foo'].length, 1, '[namedItem]' );
assert_equals( testEl.properties.namedItem('foo').getValues().length, 1, 'namedItem' );
assert_equals( testEl.properties.names.length, 1, 'names' );
}, 'the properties collection must become populated if the element is given an itemscope property');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
testEl.itemScope = false;
assert_equals( testEl.properties.length, 0, 'length' );
assert_true( !testEl.properties.item(0), 'item(0)' );
assert_true( !testEl.properties[0], '[0]' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'namedItem' );
assert_true( !testEl.properties['foo'], '[namedItem]' );
assert_equals( testEl.properties.namedItem('foo').getValues().length, 0, 'namedItem' );
assert_equals( testEl.properties.names.length, 0, 'names' );
}, 'the properties collection must become empty if the element\'s itemscope property is removed');
//properties.item and properties.length (part 1)
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.length, 5 );
}, 'properties.length must be the total number of properties');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.item(0), testEl.childNodes[0], 'item(0)' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'item(1)' );
assert_equals( testEl.properties.item(2), testEl.childNodes[1].childNodes[0], 'item(2)' );
assert_equals( testEl.properties.item(3), testEl.childNodes[2], 'item(3)' );
}, 'properties.item must give each property in tree order');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
testEl.properties.something = "another";
var names = Object.getOwnPropertyNames(testEl.properties);
assert_array_equals( names, ["0", "1", "2", "3", "foo", "bar", "baz", "qux", "something"] );
}, 'properties.item must have the right property names on it when enumerated');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.item(4), null, 'positive index' );
assert_equals( testEl.properties.item(-1), null, 'negative index' );
}, 'properties.item must give null for out of range index');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties[0], testEl.childNodes[0], '[0]' );
assert_equals( testEl.properties[1], testEl.childNodes[1], '[1]' );
assert_equals( testEl.properties[2], testEl.childNodes[1].childNodes[0], '[2]' );
assert_equals( testEl.properties[3], testEl.childNodes[2], '[3]' );
}, 'properties[index] must give each property in tree order');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties[4], window.undefined, 'positive index' );
assert_equals( testEl.properties[-1], window.undefined, 'negative index' );
}, 'properties[index] must give undefined for out of range index');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo"><div itemprop="bar"></div></div><div><div itemprop="baz"></div></div>');
assert_equals( testEl.properties.length, 2, 'length' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0)' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0]' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1].firstChild, 'properties.item(1)' );
assert_equals( testEl.properties[1], testEl.childNodes[1].firstChild, 'properties[1]' );
}, 'properties.item and length must ignore properties of nested items');
test(function () {
//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id2 id1"><div itemprop="bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
document.body.appendChild(parEl);
var propLength = testEl.properties.length;
var item0 = testEl.properties.item(0);
var square0 = testEl.properties[0];
var item1 = testEl.properties.item(1);
var square1 = testEl.properties[1];
var item2 = testEl.properties.item(2);
var square2 = testEl.properties[2];
var item3 = testEl.properties.item(3);
var square3 = testEl.properties[3];
document.body.removeChild(parEl);
assert_equals( propLength, 4, 'length' );
assert_equals( item0, parEl.firstChild, 'properties.item(0)' );
assert_equals( square0, parEl.firstChild, 'properties[0]' );
assert_equals( item1, testEl.firstChild, 'properties.item(1)' );
assert_equals( square1, testEl.firstChild, 'properties[1]' );
assert_equals( item2, parEl.childNodes[2], 'properties.item(2)' );
assert_equals( square2, parEl.childNodes[2], 'properties[2]' );
assert_equals( item3, parEl.childNodes[2].firstChild, 'properties.item(3)' );
assert_equals( square3, parEl.childNodes[2].firstChild, 'properties[3]' );
}, 'properties.item and length must see items added with itemref when attached to the document\'s DOM');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id1 id2"><div itemprop="bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 4, 'length' );
assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0)' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0]' );
assert_equals( testEl.properties.item(1), testEl.firstChild, 'properties.item(1)' );
assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1]' );
assert_equals( testEl.properties.item(2), parEl.childNodes[2], 'properties.item(2)' );
assert_equals( testEl.properties[2], parEl.childNodes[2], 'properties[2]' );
assert_equals( testEl.properties.item(3), parEl.childNodes[2].firstChild, 'properties.item(3)' );
assert_equals( testEl.properties[3], parEl.childNodes[2].firstChild, 'properties[3]' );
}, 'properties.item and length must see items added with itemref');
test(function () {
var parEl = makeEl('div',{},'<div itemscope itemref="id1"></div><div itemprop="foo" id="id1"><div itemprop="bar"></div></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[0];
assert_equals( testEl.properties.length, 2, 'length' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
document.body.appendChild(parEl)
var length = testEl.properties.length;
var item0 = testEl.properties.item(0);
var item1 = testEl.properties.item(0);
document.body.removeChild(parEl)
assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
}, 'itemref must reference the first element with a given ID');
test(function () {
var parEl = makeEl('div',{},'<div itemscope itemref="id1 id1"></div><div itemprop="foo" id="id1"><div itemprop="bar"></div></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[0];
assert_equals( testEl.properties.length, 2, 'length' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
document.body.appendChild(parEl)
var length = testEl.properties.length;
var item0 = testEl.properties.item(0);
var item1 = testEl.properties.item(0);
document.body.removeChild(parEl)
assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
}, 'itemref must ignore duplicated IDs');
test(function () {
var parEl = makeEl('div',{},'<div itemscope itemref="id0 id1"></div><div itemprop="foo" id="id1"><div itemprop="bar"></div></div>');
var testEl = parEl.childNodes[0];
assert_equals( testEl.properties.length, 2, 'length' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
document.body.appendChild(parEl)
var length = testEl.properties.length;
var item0 = testEl.properties.item(0);
var item1 = testEl.properties.item(0);
document.body.removeChild(parEl)
assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
}, 'itemref must ignore non-existent IDs');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
assert_equals( testEl.properties.length, 0 );
}, 'itemref in a dislocated tree must not reference elements from another dislocated tree');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
document.body.appendChild(dummyEl);
var tmp = testEl.properties.length;
document.body.removeChild(dummyEl);
assert_equals( tmp, 0 );
}, 'itemref in a dislocated tree must not reference elements from the main document');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
document.body.appendChild(testEl);
var tmp = testEl.properties.length;
document.body.removeChild(testEl);
assert_equals( tmp, 0 );
}, 'itemref in the main document must not reference elements from a dislocated tree');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_equals( testEl.properties.length, 1, 'length (before test)' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (before test)' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
testEl.appendChild(makeEl('div',{itemprop:'bar'}));
assert_equals( testEl.properties.length, 2, 'length after adding a child' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) after adding a child' );
assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] after adding a child' );
testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( testEl.properties.length, 3, 'length after adding a child with duplicated name' );
assert_equals( testEl.properties.item(2), testEl.childNodes[1].firstChild, 'properties.item(2) after adding a child with duplicated name' );
assert_equals( testEl.properties[2], testEl.childNodes[1].firstChild, 'properties[2] after adding a child with duplicated name' );
testEl.lastChild.removeChild(testEl.lastChild.firstChild);
assert_equals( testEl.properties.length, 2, 'length after removing a child' );
assert_true( !testEl.properties.item(2), 'properties.item(1) after removing a child' );
assert_true( !testEl.properties[2], 'properties[1] after removing a child' );
}, 'properties.item and length must update when adding property elements');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
assert_equals( testEl.properties.length, 2, 'length (before test)' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (before test)' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) (before test)' );
assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] (before test)' );
testEl.appendChild(testEl.firstChild);
assert_equals( testEl.properties.length, 2, 'length (after test)' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (after test)' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (after test)' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) (after test)' );
assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] (after test)' );
}, 'properties.item must update when re-ordering property elements, but length must not');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
assert_equals( testEl.properties.length, 1, 'length (before test)' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
testEl.lastChild.itemProp.toggle('bar');
assert_equals( testEl.properties.length, 2, 'length (after test 1)' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) after adding a token' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] after adding a token' );
assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) after adding a token' );
assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] after adding a token' );
testEl.lastChild.removeAttribute('itemprop');
assert_equals( testEl.properties.length, 1, 'length after removing an attribute' );
assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) after removing an attribute' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] after removing an attribute' );
assert_true( !testEl.properties.item(1), 'properties.item(1) after removing an attribute' );
assert_true( !testEl.properties[1], 'properties[1] after removing an attribute' );
}, 'properties.item and length must update when changing itemProp of children');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 0, 'length (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( testEl.properties.length, 2, 'length after id is created' );
assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after id is created' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after id is created' );
assert_equals( testEl.properties.item(1), parEl.firstChild.firstChild, 'properties.item(1) after id is created' );
assert_equals( testEl.properties[1], parEl.firstChild.firstChild, 'properties[1] after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( testEl.properties.length, 0, 'length after removing an attribute' );
assert_true( !testEl.properties.item(0), 'properties.item(0) after removing an attribute' );
assert_true( !testEl.properties[0], 'properties[0] after removing an attribute' );
document.body.appendChild(parEl);
var beflength = testEl.properties.length;
parEl.firstChild.id = 'id1';
var length1 = testEl.properties.length,
item0 = testEl.properties.item(0),
prop0 = testEl.properties[0],
item1 = testEl.properties.item(1),
prop1 = testEl.properties[1];
parEl.firstChild.removeAttribute('id');
var length2 = testEl.properties.length,
bitem = !testEl.properties.item(0),
bprop = !testEl.properties[0];
document.body.removeChild(parEl);
assert_equals( beflength, 0, 'length (before test) when appended to document' );
assert_equals( length1, 2, 'length after id is created when appended to document' );
assert_equals( item0, parEl.firstChild, 'properties.item(0) after id is created when appended to document' );
assert_equals( prop0, parEl.firstChild, 'properties[0] after id is created when appended to document' );
assert_equals( item1, parEl.firstChild.firstChild, 'properties.item(1) after id is created when appended to document' );
assert_equals( prop1, parEl.firstChild.firstChild, 'properties[1] after id is created when appended to document' );
assert_equals( length2, 0, 'length after removing an attribute when appended to document' );
assert_true( bitem, 'properties.item(0) after removing an attribute when appended to document' );
assert_true( bprop, 'properties[0] after removing an attribute when appended to document' );
}, 'properties.item and length must update when changing id of referenced sibling');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 1, 'length (before test)' );
assert_equals( testEl.properties.item(0), parEl.lastChild, 'properties.item(0) (before test)' );
assert_equals( testEl.properties[0], parEl.lastChild, 'properties[0] (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( testEl.properties.length, 2, 'length after id is created' );
assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after id is created' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after id is created' );
assert_equals( testEl.properties.item(1), parEl.firstChild.firstChild, 'properties.item(1) after id is created' );
assert_equals( testEl.properties[1], parEl.firstChild.firstChild, 'properties[1] after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( testEl.properties.length, 1, 'length after removing an attribute' );
assert_equals( testEl.properties.item(0), parEl.lastChild, 'properties.item(0) after removing an attribute' );
assert_equals( testEl.properties[0], parEl.lastChild, 'properties[0] after removing an attribute' );
document.body.appendChild(parEl);
var beflength = testEl.properties.length,
befitem = testEl.properties.item(0),
befprop = testEl.properties[0];
parEl.firstChild.id = 'id1';
var length1 = testEl.properties.length,
item0 = testEl.properties.item(0),
prop0 = testEl.properties[0],
item1 = testEl.properties.item(1),
prop1 = testEl.properties[1];
parEl.firstChild.removeAttribute('id');
var length2 = testEl.properties.length,
afitem = testEl.properties.item(0),
afprop = testEl.properties[0];
document.body.removeChild(parEl);
assert_equals( beflength, 1, 'length (before test) when appended to document' );
assert_equals( befitem, parEl.lastChild, 'properties.item(0) (before test)' );
assert_equals( befprop, parEl.lastChild, 'properties[0] (before test)' );
assert_equals( length1, 2, 'length after id is created when appended to document' );
assert_equals( item0, parEl.firstChild, 'properties.item(0) after id is created when appended to document' );
assert_equals( prop0, parEl.firstChild, 'properties[0] after id is created when appended to document' );
assert_equals( item1, parEl.firstChild.firstChild, 'properties.item(1) after id is created when appended to document' );
assert_equals( prop1, parEl.firstChild.firstChild, 'properties[1] after id is created when appended to document' );
assert_equals( length2, 1, 'length after removing an attribute when appended to document' );
assert_equals( afitem, parEl.lastChild, 'properties.item(0) after removing an attribute when appended to document' );
assert_equals( afprop, parEl.lastChild, 'properties[0] after removing an attribute when appended to document' );
}, 'properties.item and length must update when changing duplicated id of referenced sibling');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 0, 'length (before test)' );
testEl.itemRef.toggle('id1');
assert_equals( testEl.properties.length, 1, 'length after itemref is changed' );
assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after itemref is changed' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after itemref is changed' );
testEl.removeAttribute('itemref');
assert_equals( testEl.properties.length, 0, 'length after itemref is removed' );
assert_true( !testEl.properties.item(0), 'properties.item(0) itemref is removed' );
assert_true( !testEl.properties[0], 'properties[0] itemref is removed' );
document.body.appendChild(parEl);
var beflength = testEl.properties.length;
testEl.itemRef.toggle('id1');
var length1 = testEl.properties.length,
item0 = testEl.properties.item(0),
prop0 = testEl.properties[0];
testEl.removeAttribute('itemref');
var length2 = testEl.properties.length,
bitem = !testEl.properties.item(0),
bprop = !testEl.properties[0];
document.body.removeChild(parEl);
assert_equals( beflength, 0, 'length (before test) when appended to document' );
assert_equals( length1, 1, 'length after itemref is changed when appended to document' );
assert_equals( item0, parEl.firstChild, 'properties.item(0) after itemref is changed when appended to document' );
assert_equals( prop0, parEl.firstChild, 'properties[0] after itemref is changed when appended to document' );
assert_equals( length2, 0, 'length after itemref is removed when appended to document' );
assert_true( bitem, 'properties.item(0) after itemref is removed when appended to document' );
assert_true( bprop, 'properties[0] after itemref is removed when appended to document' );
}, 'properties.item and length must update when changing itemref to point to an element');
test(function () {
var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 0, 'length (before test)' );
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( testEl.properties.length, 1, 'length after a referenced element is added' );
assert_equals( testEl.properties.item(0), parEl.firstChild.lastChild, 'properties.item(0) after a referenced element is added' );
assert_equals( testEl.properties[0], parEl.firstChild.lastChild, 'properties[0] after a referenced element is added' );
parEl.firstChild.firstChild.itemProp.toggle('bar');
assert_equals( testEl.properties.length, 2, 'length after a referenced itemprop is changed' );
assert_equals( testEl.properties.item(0), parEl.firstChild.firstChild, 'properties.item(0) after a referenced itemprop is changed' );
assert_equals( testEl.properties[0], parEl.firstChild.firstChild, 'properties[0] after a referenced itemprop is changed' );
assert_equals( testEl.properties.item(1), parEl.firstChild.lastChild, 'properties.item(1) after a referenced itemprop is changed' );
assert_equals( testEl.properties[1], parEl.firstChild.lastChild, 'properties[1] after a referenced itemprop is changed' );
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
assert_equals( testEl.properties.length, 1, 'length after a referenced element is removed' );
assert_equals( testEl.properties.item(0), parEl.firstChild.firstChild, 'properties.item(0) after a referenced element is removed' );
assert_equals( testEl.properties[0], parEl.firstChild.firstChild, 'properties[0] after a referenced element is removed' );
assert_true( !testEl.properties.item(1), 'properties.item(1) after a referenced element is removed' );
assert_true( !testEl.properties[1], 'properties[1] after a referenced element is removed' );
parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
testEl = parEl.childNodes[1];
document.body.appendChild(parEl);
var beflength = testEl.properties.length;
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
var length1 = testEl.properties.length,
item0a = testEl.properties.item(0),
prop0a = testEl.properties[0],
targ0a = parEl.firstChild.lastChild;
parEl.firstChild.firstChild.itemProp.toggle('bar');
var length2 = testEl.properties.length,
item0b = testEl.properties.item(0),
prop0b = testEl.properties[0];
item1b = testEl.properties.item(1),
prop1b = testEl.properties[1],
targ0b = parEl.firstChild.firstChild,
targ1b = parEl.firstChild.lastChild;
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
var length3 = testEl.properties.length,
item0c = testEl.properties.item(0),
prop0c = testEl.properties[0];
item1c = testEl.properties.item(1),
prop1c = testEl.properties[1],
targ0c = parEl.firstChild.firstChild;
document.body.removeChild(parEl);
assert_equals( beflength, 0, 'length (before test) when appended to document' );
assert_equals( length1, 1, 'length after a referenced element is added when appended to document' );
assert_equals( item0a, targ0a, 'properties.item(0) after a referenced element is added when appended to document' );
assert_equals( prop0a, targ0a, 'properties[0] after a referenced element is added when appended to document' );
assert_equals( length2, 2, 'length after a referenced itemprop is changed when appended to document' );
assert_equals( item0b, targ0b, 'properties.item(0) after a referenced itemprop is changed when appended to document' );
assert_equals( prop0b, targ0b, 'properties[0] after a referenced itemprop is changed when appended to document' );
assert_equals( item1b, targ1b, 'properties.item(1) after a referenced itemprop is changed when appended to document' );
assert_equals( prop1b, targ1b, 'properties[1] after a referenced itemprop is changed when appended to document' );
assert_equals( length3, 1, 'length after a referenced element is removed when appended to document' );
assert_equals( item0c, targ0c, 'properties.item(0) after a referenced element is removed when appended to document' );
assert_equals( prop0c, targ0c, 'properties[0] after a referenced element is removed when appended to document' );
assert_true( !item1c, 'properties.item(1) after a referenced element is removed when appended to document' );
assert_true( !prop1c, 'properties[1] after a referenced element is removed when appended to document' );
}, 'properties.item and length must update when changing children of elements referenced through itemref');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="foo"></div></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 2, 'length (before test)' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] (before test)' );
assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] (before test)' );
document.body.appendChild(testEl);
var step1length = testEl.properties.length;
var step1prop0 = testEl.properties[0];
var step1prop1 = testEl.properties[1];
parEl.appendChild(testEl);
assert_equals( step1length, 1, 'length after changing parent' );
assert_equals( step1prop0, testEl.firstChild, 'properties[0] after changing parent' );
assert_true( !step1prop1, 'properties[1] after changing parent' );
assert_equals( testEl.properties.length, 2, 'length after re-parenting' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after re-parenting' );
assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] after re-parenting' );
document.body.appendChild(parEl);
var step2length = testEl.properties.length;
var step2prop0 = testEl.properties[0];
var step2prop1 = testEl.properties[1];
document.createElement('div').appendChild(testEl);
var step3length = testEl.properties.length;
var step3prop0 = testEl.properties[0];
var step3prop1 = testEl.properties[1];
parEl.appendChild(testEl);
var step4length = testEl.properties.length;
var step4prop0 = testEl.properties[0];
var step4prop1 = testEl.properties[1];
document.body.removeChild(parEl);
assert_equals( step2length, 2, 'length (before test) when appended to document' );
assert_equals( step2prop0, parEl.firstChild, 'properties[0] (before test) when appended to document' );
assert_equals( step2prop1, testEl.firstChild, 'properties[1] (before test) when appended to document' );
assert_equals( step3length, 1, 'length after changing parent when appended to document' );
assert_equals( step3prop0, testEl.firstChild, 'properties[0] after changing parent when appended to document' );
assert_true( !step3prop1, 'properties[1] after changing parent when appended to document' );
assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
assert_equals( step4prop0, parEl.firstChild, 'properties[0] after re-parenting when appended to document' );
assert_equals( step4prop1, testEl.firstChild, 'properties[1] after re-parenting when appended to document' );
}, 'properties.item and length must update when appending elements with itemref to different parents');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
assert_equals( testEl.properties.length, 1, 'length (before test)' );
assert_equals( testEl.properties.item(0), testEl.firstChild.firstChild, 'properties.item(0) (before test)' );
assert_equals( testEl.properties[0], testEl.firstChild.firstChild, 'properties[0] (before test)' );
testEl.firstChild.itemScope = true;
assert_equals( testEl.properties.length, 0, 'length after setting itemscope' );
assert_true( !testEl.properties.item(0), 'properties.item(0) after setting itemscope' );
assert_true( !testEl.properties[0], 'properties[0] after setting itemscope' );
testEl.firstChild.removeAttribute('itemscope');
assert_equals( testEl.properties.length, 1, 'length after removing itemscope attribute' );
assert_equals( testEl.properties.item(0), testEl.firstChild.firstChild, 'properties.item(0) after removing itemscope attribute' );
assert_equals( testEl.properties[0], testEl.firstChild.firstChild, 'properties[0] after removing itemscope attribute' );
}, 'properties.item and length must update when changing itemscope of children');
//properties.namedItem
test(function () {
assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo'), 'object' );
}, 'the namedItem must return an object');
test(function () {
assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties['foo'], 'object' );
}, '.properties[] must also act as .properties.namedItem() when there are matching properties');
test(function () {
assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'').properties.namedItem('foo'), 'object' );
}, 'the namedItem must return an object even if there are no matching properties');
test(function () {
assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'').properties['foo'], 'undefined' );
}, '.properties[] must return undefined when no property exists with the given name');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
var PNL = testEl.properties.namedItem('foo');
assert_equals( PNL, testEl.properties.namedItem('foo'), 'before modification' );
testEl.innerHTML = '';
assert_equals( PNL, testEl.properties.namedItem('foo'), 'after modification' );
}, 'namedItem must return the same object for the same property name');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_false( testEl.properties.namedItem('foo') == testEl.properties.namedItem('bar') );
}, 'namedItem must return a different object for a different property name');
test(function () {
assert_false( makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo') == makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo') );
}, 'namedItem must return a different object for different elements with the same property name');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_equals( testEl.properties.namedItem('foo'), testEl.properties['foo'] );
}, 'namedItem() and properties[] must return the same object for the same property name');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_true( testEl.properties.namedItem('foo') instanceof PropertyNodeList, 'instanceof PropertyNodeList' );
assert_true( testEl.properties.namedItem('foo') instanceof NodeList, 'instanceof NodeList' );
PropertyNodeList.prototype.customProperty = true;
NodeList.prototype.anotherCustomProperty = true;
assert_true( testEl.properties.namedItem('foo').customProperty, 'inheritance from PropertyNodeList' );
assert_true( testEl.properties.namedItem('foo').anotherCustomProperty, 'inheritance from NodeList' );
PropertyNodeList.prototype.anotherCustomProperty = false;
assert_false( testEl.properties.anotherCustomProperty, 'shadowing by PropertyNodeList' );
}, 'the properties property must implement PropertyNodeList and NodeList');
test(function () {
var failed = false, elem = makeEl('div',{itemscope:'itemscope'});
try {
elem.properties.namedItem = 'pass';
} catch(e) {
failed = e;
}
assert_equals(elem.properties.namedItem,'pass');
assert_false(failed,'an error was thrown');
}, 'the namedItem property must be read/write');
test(function () {
//also tests for sort ordering, which is fairly simple in this case
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="baz qux"></div></div><div itemprop="foo"></div>');
assert_equals( testEl.properties.namedItem('foo').length, 2, 'length of foo' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'length of bar' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'length of baz' );
assert_equals( testEl.properties.namedItem('qux').length, 1, 'length of qux' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'first foo' );
assert_equals( testEl.properties.namedItem('foo')[1], testEl.lastChild, 'last foo' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.childNodes[1], 'bar' );
assert_equals( testEl.properties.namedItem('baz')[0], testEl.childNodes[1].firstChild, 'baz' );
assert_equals( testEl.properties.namedItem('qux')[0], testEl.childNodes[1].firstChild, 'qux' );
}, 'PropertyNodeList must contain the correct properties');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="FOO"></div><div itemprop="foo FOO foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.namedItem('foo').length, 2, 'length of foo' );
assert_equals( testEl.properties.namedItem('FOO').length, 2, 'length of FOO' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'first foo' );
assert_equals( testEl.properties.namedItem('foo')[1], testEl.childNodes[1].lastChild, 'last foo' );
assert_equals( testEl.properties.namedItem('FOO')[0], testEl.childNodes[1].firstChild, 'first FOO' );
assert_equals( testEl.properties.namedItem('FOO')[1], testEl.childNodes[1].lastChild, 'last FOO' );
}, 'PropertyNodeList must be case sensitive');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo bar"></div>');
assert_equals( testEl.properties.namedItem('foo bar').length, 0, 'space' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\tbar"></div>');
assert_equals( testEl.properties.namedItem('foo\tbar').length, 0, 'tab' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\rbar"></div>');
assert_equals( testEl.properties.namedItem('foo\rbar').length, 0, 'carriage return' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\nbar"></div>');
assert_equals( testEl.properties.namedItem('foo\nbar').length, 0, 'newline' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\fbar"></div>');
assert_equals( testEl.properties.namedItem('foo\fbar').length, 0, 'formfeed' );
}, 'namedItem must not match property names containing whitespace');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>åøæÅØÆ"></div>');
assert_equals( testEl.properties.namedItem('|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>åøæÅØÆ').length, 1 );
}, 'namedItem must match property names containing other special characters');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'});
var PNL = testEl.properties.namedItem('foo');
testEl.innerHTML = '<div itemprop="foo"></div>';
assert_equals( PNL.length, 1 );
assert_equals( PNL[0], testEl.firstChild );
}, 'PropertyNodeList must be live');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemscope><div itemprop="foo"></div><div itemprop="bar"></div></div>');
assert_equals( testEl.properties.namedItem('foo').length, 1, 'length of foo' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'item 0' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'length of bar' );
}, 'PropertyNodeList must ignore properties of nested items');
test(function () {
//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms - not that that should make much difference here
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id2 id1"><div itemprop="foo bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
document.body.appendChild(parEl);
var fooLength = testEl.properties.namedItem('foo').length;
var barLength = testEl.properties.namedItem('bar').length;
var bazLength = testEl.properties.namedItem('baz').length;
var quxLength = testEl.properties.namedItem('qux').length;
var foo0 = testEl.properties.namedItem('foo')[0];
var foo1 = testEl.properties.namedItem('foo')[1];
var bar0 = testEl.properties.namedItem('bar')[0];
var baz0 = testEl.properties.namedItem('baz')[0];
var qux0 = testEl.properties.namedItem('qux')[0];
document.body.removeChild(parEl);
assert_equals( fooLength, 2, 'foo length' );
assert_equals( barLength, 1, 'bar length' );
assert_equals( bazLength, 1, 'baz length' );
assert_equals( quxLength, 1, 'qux length' );
assert_equals( foo0, parEl.firstChild, 'foo 0' );
assert_equals( foo1, testEl.firstChild, 'foo 1' );
assert_equals( bar0, testEl.firstChild, 'bar 0' );
assert_equals( baz0, parEl.lastChild, 'baz 0' );
assert_equals( qux0, parEl.lastChild.firstChild, 'qux 0' );
}, 'PropertyNodeList must see items added with itemref when attached to the document\'s DOM');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id1 id2"><div itemprop="foo bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.namedItem('foo').length, 2, 'foo length' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz length' );
assert_equals( testEl.properties.namedItem('qux').length, 1, 'qux length' );
assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo 0' );
assert_equals( testEl.properties.namedItem('foo')[1], testEl.firstChild, 'foo 1' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar 0' );
assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz 0' );
assert_equals( testEl.properties.namedItem('qux')[0], parEl.lastChild.firstChild, 'qux 0' );
}, 'PropertyNodeList must see items added with itemref');
test(function () {
//this one also tests the live object just in case - further ones will not always do this as its live status will already have been well established
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
var PNL = testEl.properties.namedItem('foo');
testEl.removeAttribute('itemscope');
assert_equals( testEl.properties.namedItem('foo').length, 0, 'removing attribute' );
assert_equals( PNL.length, 0, 'removing attribute (live)' );
assert_true( !testEl.properties['foo'], 'removing attribute []' );
testEl.itemScope = true;
assert_equals( testEl.properties.namedItem('foo').length, 1, 'setting itemScope' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'property 0 after setting itemScope' );
assert_equals( PNL.length, 1, 'setting itemScope (live)' );
assert_equals( PNL[0], testEl.firstChild, 'property 0 after setting itemScope (live)' );
assert_false( !testEl.properties['foo'], 'setting itemScope []' );
}, 'PropertyNodeList must update when adding itemscope on the root');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length (before test)' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 (before test)' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'bar length (before test)' );
testEl.appendChild(makeEl('div',{itemprop:'bar'}));
assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length after adding a child' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 after adding a child' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after adding a child' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'bar 0 after adding a child' );
testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( testEl.properties.namedItem('foo').length, 2, 'foo length after adding a child with duplicated name' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 after adding a child with duplicated name' );
assert_equals( testEl.properties.namedItem('foo')[1], testEl.lastChild.firstChild, 'foo 1 after adding a child with duplicated name' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after adding a child with duplicated name' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'bar 0 after adding a child with duplicated name' );
testEl.lastChild.removeChild(testEl.lastChild.firstChild);
assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length after removing a child' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after removing a child' );
}, 'PropertyNodeList must update when adding property elements');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="foo"></div>');
var PNL = testEl.properties.namedItem('foo');
assert_equals( PNL[0], testEl.firstChild, 'item 0 (before test)' );
assert_equals( PNL[1], testEl.lastChild, 'item 1 (before test)' );
testEl.appendChild(testEl.firstChild);
assert_equals( PNL[0], testEl.firstChild, 'item 0 (after test)' );
assert_equals( PNL[1], testEl.lastChild, 'item 1 (after test)' );
}, 'PropertyNodeList must update when re-ordering property elements');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
assert_equals( PNLfoo.length, 1, 'foo length (before test)' );
assert_equals( PNLbar.length, 0, 'bar length (before test)' );
assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] (before test)' );
testEl.lastChild.itemProp.toggle('bar');
assert_equals( PNLfoo.length, 1, 'foo length after adding a token' );
assert_equals( PNLbar.length, 1, 'bar length after adding a token' );
assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after adding a token' );
assert_equals( PNLbar[0], testEl.lastChild, 'bar[0] after adding a token' );
testEl.lastChild.itemProp.add('foo');
assert_equals( PNLfoo.length, 2, 'foo length after adding a duplicated token' );
assert_equals( PNLbar.length, 1, 'bar length after adding a duplicated token' );
assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after adding a duplicated token' );
assert_equals( PNLfoo[1], testEl.lastChild, 'foo[1] after adding a duplicated token' );
assert_equals( PNLbar[0], testEl.lastChild, 'bar[0] after adding a duplicated token' );
testEl.lastChild.removeAttribute('itemprop');
assert_equals( PNLfoo.length, 1, 'foo length after removing an attribute' );
assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after removing an attribute' );
}, 'PropertyNodeList must update when changing itemProp of children');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
assert_equals( PNLbar.length, 0, 'bar length (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( PNLfoo.length, 1, 'foo length after id is created' );
assert_equals( PNLbar.length, 1, 'bar length after id is created' );
assert_equals( PNLfoo[0], parEl.firstChild, 'foo[0] after id is created' );
assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar[0] after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( PNLfoo.length, 0, 'foo length after removing an attribute' );
assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
document.body.appendChild(parEl);
var fooLength0 = PNLfoo.length;
var barLength0 = PNLbar.length;
parEl.firstChild.id = 'id1';
var fooLength1 = PNLfoo.length;
var barLength1 = PNLbar.length;
var foo0 = PNLfoo[0];
var bar0 = PNLbar[0];
parEl.firstChild.removeAttribute('id');
var fooLength2 = PNLfoo.length;
var barLength2 = PNLbar.length;
document.body.removeChild(parEl);
assert_equals( fooLength0, 0, 'foo length (before test) when appended to document' );
assert_equals( barLength0, 0, 'bar length (before test) when appended to document' );
assert_equals( fooLength1, 1, 'foo length after id is created when appended to document' );
assert_equals( barLength1, 1, 'bar length after id is created when appended to document' );
assert_equals( foo0, parEl.firstChild, 'foo[0] after id is created when appended to document' );
assert_equals( bar0, parEl.firstChild.firstChild, 'bar[0] after id is created when appended to document' );
assert_equals( fooLength2, 0, 'foo length after removing an attribute when appended to document' );
assert_equals( barLength2, 0, 'bar length after removing an attribute when appended to document' );
}, 'PropertyNodeList must update when changing id of referenced sibling');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[1];
var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar'), PNLbaz = testEl.properties.namedItem('baz');
assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
assert_equals( PNLbar.length, 0, 'bar length (before test)' );
assert_equals( PNLbaz.length, 1, 'baz length (before test)' );
assert_equals( PNLbaz[0], parEl.lastChild, 'baz[0] (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( PNLfoo.length, 1, 'foo length after id is created' );
assert_equals( PNLbar.length, 1, 'bar length after id is created' );
assert_equals( PNLbaz.length, 0, 'baz length after id is created' );
assert_equals( PNLfoo[0], parEl.firstChild, 'foo[0] after id is created' );
assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar[0] after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( PNLfoo.length, 0, 'foo length after removing an attribute' );
assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
assert_equals( PNLbaz.length, 1, 'baz length after removing an attribute' );
assert_equals( PNLbaz[0], parEl.lastChild, 'baz[0] after removing an attribute' );
document.body.appendChild(parEl);
var fooLength0 = PNLfoo.length;
var barLength0 = PNLbar.length;
var bazLength0 = PNLbaz.length;
var baz0 = PNLbaz[0];
parEl.firstChild.id = 'id1';
var fooLength1 = PNLfoo.length;
var barLength1 = PNLbar.length;
var bazLength1 = PNLbaz.length;
var foo0 = PNLfoo[0];
var bar0 = PNLbar[0];
parEl.firstChild.removeAttribute('id');
var fooLength2 = PNLfoo.length;
var barLength2 = PNLbar.length;
var bazLength2 = PNLbaz.length;
var baz1 = PNLbaz[0];
document.body.removeChild(parEl);
assert_equals( fooLength0, 0, 'foo length (before test) when appended to document' );
assert_equals( barLength0, 0, 'bar length (before test) when appended to document' );
assert_equals( bazLength0, 1, 'baz length (before test)' );
assert_equals( baz0, parEl.lastChild, 'baz[0] (before test)' );
assert_equals( fooLength1, 1, 'foo length after id is created when appended to document' );
assert_equals( barLength1, 1, 'bar length after id is created when appended to document' );
assert_equals( bazLength1, 0, 'baz length after id is created' );
assert_equals( foo0, parEl.firstChild, 'foo[0] after id is created when appended to document' );
assert_equals( bar0, parEl.firstChild.firstChild, 'bar[0] after id is created when appended to document' );
assert_equals( fooLength2, 0, 'foo length after removing an attribute when appended to document' );
assert_equals( barLength2, 0, 'bar length after removing an attribute when appended to document' );
assert_equals( bazLength2, 1, 'baz length after removing an attribute' );
assert_equals( baz0, parEl.lastChild, 'baz[0] after removing an attribute' );
}, 'PropertyNodeList must update when changing duplicated id of referenced sibling');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
var testEl = parEl.childNodes[1];
var PNL = testEl.properties.namedItem('foo');
assert_equals( PNL.length, 0, 'length (before test)' );
testEl.itemRef.toggle('id1');
assert_equals( PNL.length, 1, 'length after itemref is changed' );
assert_equals( PNL[0], parEl.firstChild, 'item 0 after itemref is changed' );
testEl.removeAttribute('itemref');
assert_equals( PNL.length, 0, 'length after itemref is removed' );
assert_true( !PNL[0], 'item 0 after itemref is removed' );
document.body.appendChild(parEl);
var length0 = PNL.length;
testEl.itemRef.toggle('id1');
var length1 = PNL.length;
var foo0 = PNL[0];
testEl.removeAttribute('itemref');
var length2 = PNL.length;
var foo1 = PNL[0];
document.body.removeChild(parEl);
assert_equals( length0, 0, 'length (before test) when appended to document' );
assert_equals( length1, 1, 'length after itemref is changed when appended to document' );
assert_equals( foo0, parEl.firstChild, 'item 0 after itemref is changed when appended to document' );
assert_equals( length2, 0, 'length after itemref is removed when appended to document' );
assert_true( !foo1, 'item 0 after itemref is removed when appended to document' );
}, 'PropertyNodeList must update when changing itemref to point to an element');
test(function () {
var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
assert_equals( PNLbar.length, 0, 'bar length (before test)' );
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( PNLfoo.length, 1, 'foo length after a referenced element is added' );
assert_equals( PNLbar.length, 0, 'bar length after a referenced element is added' );
assert_equals( PNLfoo.item(0), parEl.firstChild.lastChild, 'foo 0 after a referenced element is added' ); //uses item just for the fun of it
parEl.firstChild.firstChild.itemProp.toggle('bar');
assert_equals( PNLfoo.length, 1, 'foo length after a referenced itemprop is changed' );
assert_equals( PNLbar.length, 1, 'bar length after a referenced itemprop is changed' );
assert_equals( PNLfoo[0], parEl.firstChild.lastChild, 'foo 0 after a referenced element is added' );
assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar 0 after a referenced element is added' );
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
assert_equals( PNLfoo.length, 1, 'foo length after a referenced element is removed' );
assert_equals( PNLbar.length, 0, 'bar length after a referenced element is removed' );
assert_equals( PNLfoo[0], parEl.firstChild.firstChild, 'foo 0 after a referenced element is removed' );
assert_true( !PNLbar[0], 'bar 0 after a referenced element is removed' );
parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
testEl = parEl.childNodes[1];
PNLfoo = testEl.properties.namedItem('foo');
PNLbar = testEl.properties.namedItem('bar');
document.body.appendChild(parEl);
var step1fooLength = PNLfoo.length;
var step1barLength = PNLbar.length;
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
var step2fooLength = PNLfoo.length;
var step2barLength = PNLbar.length;
var step2foo0 = PNLfoo.item(0); //uses item just for the fun of it
var step2fooExpected = parEl.firstChild.lastChild;
parEl.firstChild.firstChild.itemProp.toggle('bar');
var step3fooLength = PNLfoo.length;
var step3barLength = PNLbar.length;
var step3foo0 = PNLfoo[0];
var step3bar0 = PNLbar[0];
var step3fooExpected = parEl.firstChild.lastChild;
var step3barExpected = parEl.firstChild.firstChild;
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
var step4fooLength = PNLfoo.length;
var step4barLength = PNLbar.length;
var step4foo0 = PNLfoo[0];
var step4bar0 = PNLbar[0];
var step4fooExpected = parEl.firstChild.firstChild;
document.body.removeChild(parEl);
assert_equals( step1fooLength, 0, 'foo length (before test) when appended to document' );
assert_equals( step1barLength, 0, 'bar length (before test) when appended to document' );
assert_equals( step2fooLength, 1, 'foo length after a referenced element is added when appended to document' );
assert_equals( step2barLength, 0, 'bar length after a referenced element is added when appended to document' );
assert_equals( step2foo0, step2fooExpected, 'foo 0 after a referenced element is added when appended to document' );
assert_equals( step3fooLength, 1, 'foo length after a referenced itemprop is changed when appended to document' );
assert_equals( step3barLength, 1, 'bar length after a referenced itemprop is changed when appended to document' );
assert_equals( step3foo0, step3fooExpected, 'foo 0 after a referenced element is added when appended to document' );
assert_equals( step3bar0, step3barExpected, 'bar 0 after a referenced element is added when appended to document' );
assert_equals( step4fooLength, 1, 'foo length after a referenced element is removed when appended to document' );
assert_equals( step4barLength, 0, 'bar length after a referenced element is removed when appended to document' );
assert_equals( step4foo0, step4fooExpected, 'foo 0 after a referenced element is removed when appended to document' );
assert_true( !step4bar0, 'bar 0 after a referenced element is removed when appended to document' );
}, 'PropertyNodeList must update when changing children of elements referenced through itemref');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="foo"></div></div>');
var testEl = parEl.childNodes[1];
var PNL = testEl.properties.namedItem('foo');
assert_equals( PNL.length, 2, 'length (before test)' );
assert_equals( PNL[0], parEl.firstChild, 'item 0 (before test)' );
assert_equals( PNL[1], testEl.firstChild, 'item 1 (before test)' );
document.body.appendChild(testEl);
var step1length = PNL.length;
var step1prop0 = PNL[0];
var step1prop1 = PNL[1];
parEl.appendChild(testEl);
assert_equals( step1length, 1, 'length after changing parent' );
assert_equals( step1prop0, testEl.firstChild, 'item 0 after changing parent' );
assert_true( !step1prop1, 'item 1 after changing parent' );
assert_equals( PNL.length, 2, 'length after re-parenting' );
assert_equals( PNL[0], parEl.firstChild, 'item 0 after re-parenting' );
assert_equals( PNL[1], testEl.firstChild, 'item 1 after re-parenting' );
document.body.appendChild(parEl);
var step2length = PNL.length;
var step2prop0 = PNL[0];
var step2prop1 = PNL[1];
document.createElement('div').appendChild(testEl);
var step3length = PNL.length;
var step3prop0 = PNL[0];
var step3prop1 = PNL[1];
parEl.appendChild(testEl);
var step4length = PNL.length;
var step4prop0 = PNL[0];
var step4prop1 = PNL[1];
document.body.removeChild(parEl);
assert_equals( step2length, 2, 'length (before test) when appended to document' );
assert_equals( step2prop0, parEl.firstChild, 'item 0 (before test) when appended to document' );
assert_equals( step2prop1, testEl.firstChild, 'item 1 (before test) when appended to document' );
assert_equals( step3length, 1, 'length after changing parent when appended to document' );
assert_equals( step3prop0, testEl.firstChild, 'item 0 after changing parent when appended to document' );
assert_true( !step3prop1, 'item 1 after changing parent when appended to document' );
assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
assert_equals( step4prop0, parEl.firstChild, 'item 0 after re-parenting when appended to document' );
assert_equals( step4prop1, testEl.firstChild, 'item 1 after re-parenting when appended to document' );
}, 'PropertyNodeList must update when appending elements with itemref to different parents');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
var PNL = testEl.properties.namedItem('foo');
assert_equals( PNL.length, 1, 'length (before test)' );
assert_equals( PNL[0], testEl.firstChild.firstChild, 'foo 0 (before test)' );
testEl.firstChild.itemScope = true;
assert_equals( PNL.length, 0, 'length after setting itemscope' );
assert_true( !PNL[0], 'foo 0 after setting itemscope' );
testEl.firstChild.removeAttribute('itemscope');
assert_equals( PNL.length, 1, 'length after removing itemscope attribute' );
assert_equals( PNL[0], testEl.firstChild.firstChild, 'foo 0 after removing itemscope attribute' );
}, 'PropertyNodeList must update when changing itemscope of children');
//PropertyNodeList.getValues
test(function () {
var valuesArray = makeEl('div',{}).properties.namedItem('foo').getValues();
assert_true( valuesArray instanceof Array, 'instanceof test' );
Array.prototype.customProp = true;
assert_true( valuesArray.customProp, 'inheritance test' );
}, 'getValues must return an array');
test(function () {
var testEl = makeEl('div',{});
var props = testEl.properties.namedItem('foo');
assert_not_equals( props.getValues(), props.getValues() );
}, 'getValues must always return a newly constructed array');
test(function () {
var parEl = makeEl('div',{},'<div id="id1"></div>');
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
parEl.appendChild(testEl);
testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
parEl.appendChild(makeEl('time',{itemprop:'foo',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
var PNL = testEl.properties.namedItem('foo');
var valuesArray = PNL.getValues();
for( var i = 0; i < PNL.length; i++ ) {
assert_equals( valuesArray[i], PNL[i].itemValue, 'property index ' + i + ', tag ' + PNL[i].tagName );
}
assert_equals( valuesArray.length, 20, 'length' );
}, 'getValues array must contain the same item values as itemValue would return for the given properties');
test(function () {
var parEl = makeEl('div',{},'<div id="id1"></div>');
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
parEl.appendChild(testEl);
testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
parEl.appendChild(makeEl('time',{itemprop:'foo',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
var PNL = testEl.properties.namedItem('foo');
var valuesArray = PNL.getValues();
var staticArray = [];
for( var i = 0; i < PNL.length; i++ ) {
staticArray[i] = PNL[i].itemValue;
}
testEl.innerHTML = '';
parEl.firstChild.firstChild.childNodes[1].itemScope = false;
assert_equals( valuesArray.length, staticArray.length, 'length after modification' );
for( var j = 0; j < staticArray.length; j++ ) {
assert_equals( valuesArray[j], staticArray[j], 'property index ' + j );
}
assert_equals( valuesArray[1], parEl.firstChild.firstChild.childNodes[1], 'retaining pointer after modification' );
staticArray = null;
parEl.firstChild.firstChild.innerHTML = '';
assert_equals( valuesArray[1] && valuesArray[1].nodeType, 1, 'retaining pointer after removal' );
}, 'getValues array must not be live');
//names
test(function () {
assert_equals( typeof makeEl('div',{}).properties.names, 'object' );
}, 'the names property must be an object');
test(function () {
var testEl = makeEl('div',{});
assert_true( testEl.properties.names instanceof DOMStringList, 'instanceof DOMStringList' );
DOMStringList.prototype.stringCustomProperty = true;
assert_true( testEl.properties.names.stringCustomProperty, 'inheritance from DOMStringList' );
}, 'the names property must implement DOMStringList');
test(function () {
var failed = false, elem = makeEl('div',{itemscope:'itemscope'}), realList = elem.properties.names;
try {
elem.properties.names = '';
} catch(e) {
failed = e;
}
assert_equals(elem.properties.names,realList);
assert_false(failed,'an error was thrown');
}, 'the names property must be read-only');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.properties.names, testEl.properties.names );
}, 'the names property must always reference the same object');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.properties.names.item(0), null, 'item(0)' );
assert_equals( testEl.properties.names.item(-1), null, 'item(-1)' );
}, 'names.item() must return null for out of range indexes');
test(function () {
var testEl = makeEl('div',{});
assert_equals( testEl.properties.names[0], window.undefined, '[0]' );
assert_equals( testEl.properties.names[-1], window.undefined, '[-1]' );
}, 'names[index] must return undefined for out of range indexes');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
assert_equals( testEl.properties.names.length, 0, 'length' );
assert_true( !testEl.properties.names.item(0), 'item(0)' );
assert_true( !testEl.properties.names[0], '[0]' );
assert_false( testEl.properties.names.contains('foo'), 'contains' );
}, 'the names collection must be empty if the element does not have an itemscope property');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
testEl.itemScope = true;
assert_equals( testEl.properties.names.length, 1, 'length' );
assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
assert_equals( testEl.properties.names[0], 'foo', '[0]' );
assert_true( testEl.properties.names.contains('foo'), 'contains' );
}, 'the names collection must become populated if the element is given an itemscope property');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
testEl.itemScope = false;
assert_equals( testEl.properties.names.length, 0, 'length' );
assert_true( !testEl.properties.names.item(0), 'item(0)' );
assert_true( !testEl.properties.names[0], '[0]' );
assert_false( testEl.properties.names.contains('foo'), 'contains' );
}, 'the names collection must become empty if the element\'s itemscope property is removed');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
testEl.properties.names.item = 'test';
testEl.properties.names.contains = 'test';
assert_equals( testEl.properties.names.item, 'test', 'item' );
assert_equals( testEl.properties.names.contains, 'test', 'contains' );
}, 'the names.item and names.contains methods should be overwriteable');
test(function () {
var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
testEl.properties.names.localCustomProperty = 'test';
assert_equals( testEl.properties.names.localCustomProperty, 'test' );
}, 'the names.customProperty should be writeable');
test(function () {
//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
//ES5 makes [[Put]] fail but not throw
var failed = false;
var elem = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
try {
elem.properties.names.length = 0;
} catch(e) {
failed = e;
}
assert_equals(elem.properties.names.length,1);
assert_false(failed,'an error was thrown');
}, 'names.length must be read-only');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.names.length, 4 );
}, 'names.length must be the total number of property names');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div><div itemprop="foo"></div></div><div itemprop="baz \t\r\n\fqux"></div>');
assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
assert_equals( testEl.properties.names.item(1), 'bar', 'item(1)' );
assert_equals( testEl.properties.names.item(2), 'baz', 'item(2)' );
assert_equals( testEl.properties.names.item(3), 'qux', 'item(3)' );
assert_equals( testEl.properties.names[0], 'foo', '[0]' );
assert_equals( testEl.properties.names[1], 'bar', '[1]' );
assert_equals( testEl.properties.names[2], 'baz', '[2]' );
assert_equals( testEl.properties.names[3], 'qux', '[3]' );
}, 'names.item must give each property name in tree order');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar BAR bar"><div itemprop="FOO"></div><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_equals( testEl.properties.names.length, 6, 'length' );
assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
assert_equals( testEl.properties.names.item(1), 'bar', 'item(1)' );
assert_equals( testEl.properties.names.item(2), 'BAR', 'item(2)' );
assert_equals( testEl.properties.names.item(3), 'FOO', 'item(3)' );
assert_equals( testEl.properties.names.item(4), 'baz', 'item(4)' );
assert_equals( testEl.properties.names.item(5), 'qux', 'item(5)' );
assert_equals( testEl.properties.names[0], 'foo', '[0]' );
assert_equals( testEl.properties.names[1], 'bar', '[1]' );
assert_equals( testEl.properties.names[2], 'BAR', '[2]' );
assert_equals( testEl.properties.names[3], 'FOO', '[3]' );
assert_equals( testEl.properties.names[4], 'baz', '[4]' );
assert_equals( testEl.properties.names[5], 'qux', '[5]' );
}, 'names must be case sensitive');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="FOO"></div><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
assert_true( testEl.properties.names.contains('foo'), 'foo' );
assert_true( testEl.properties.names.contains('FOO'), 'FOO' );
assert_true( testEl.properties.names.contains('bar'), 'bar' );
assert_false( testEl.properties.names.contains('BAR'), 'BAR' );
assert_true( testEl.properties.names.contains('baz'), 'baz' );
assert_true( testEl.properties.names.contains('qux'), 'qux' );
assert_false( testEl.properties.names.contains('madeup'), 'madeup' );
}, 'names.contains must return boolean if the name exists');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="1"></div>');
assert_equals( testEl.properties.names.item('1'), null );
}, 'names.item must cast to number');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="1"></div>');
assert_true( testEl.properties.names.contains({ valueOf: function () { return 2; }, toString: function () { return 'foo'; } }), 'object' );
assert_true( testEl.properties.names.contains(1), 'number' );
}, 'names.contains must cast to string');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
var namesList = testEl.properties.names;
testEl.innerHTML = '<div itemprop="baz"></div>';
assert_equals( testEl.properties.names.length, 1, 'length' );
assert_equals( testEl.properties.names[0], 'baz', '[0]' );
}, 'the names collection must be live');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>åøæÅØÆ"></div>');
assert_equals( testEl.properties.names[0], '|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>åøæÅØÆ' );
}, 'names must reflect property names containing special characters');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemscope><div itemprop="bar"></div></div>');
assert_equals( testEl.properties.names.length, 1, 'length' );
assert_equals( testEl.properties.names[0], 'foo', '[0]' );
assert_true( testEl.properties.names.contains('foo'), 'contains(foo)' );
assert_false( testEl.properties.names.contains('bar'), 'contains(bar)' );
}, 'names must ignore properties of nested items');
test(function () {
//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id2 id1"><div itemprop="bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
document.body.appendChild(parEl);
var length = testEl.properties.names.length;
var names0 = testEl.properties.names[0];
var names1 = testEl.properties.names[1];
var names2 = testEl.properties.names[2];
var names3 = testEl.properties.names[3];
document.body.removeChild(parEl);
assert_equals( length, 4, 'length' );
assert_equals( names0, 'foo', 'names[0]' );
assert_equals( names1, 'bar', 'names[1]' );
assert_equals( names2, 'baz', 'names[2]' );
assert_equals( names3, 'qux', 'names[3]' );
}, 'names must see items added with itemref when attached to the document\'s DOM');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo" id="id1"></div><div itemscope itemref="id1 id2"><div itemprop="bar"></div></div><div itemprop="baz" id="id2"><div itemprop="qux"></div></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.names.length, 4, 'length' );
assert_equals( testEl.properties.names[0], 'foo', 'names[0]' );
assert_equals( testEl.properties.names[1], 'bar', 'names[1]' );
assert_equals( testEl.properties.names[2], 'baz', 'names[2]' );
assert_equals( testEl.properties.names[3], 'qux', 'names[3]' );
}, 'names must see items added with itemref');
test(function () {
//this one also tests the live object just in case - further ones will not always do this as its live status will already have been well established
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
var DSL = testEl.properties.names;
testEl.removeAttribute('itemscope');
assert_equals( testEl.properties.names.length, 0, 'removing attribute' );
assert_equals( DSL.length, 0, 'removing attribute (live)' );
assert_true( !testEl.properties.names[0], 'removing attribute [0]' );
assert_true( !DSL[0], 'removing attribute [0] (live)' );
testEl.itemScope = true;
assert_equals( testEl.properties.names.length, 1, 'setting itemScope' );
assert_equals( DSL.length, 1, 'setting itemScope (live)' );
assert_equals( testEl.properties.names[0], 'foo', 'names[0] after setting itemScope' );
assert_equals( DSL[0], 'foo', 'names[0] after setting itemScope (live)' );
}, 'names must update when adding itemscope on the root');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
assert_equals( testEl.properties.names.length, 1, 'length (before test)' );
assert_equals( testEl.properties.names[0], 'foo', 'item 0 (before test)' );
testEl.appendChild(makeEl('div',{itemprop:'bar'}));
assert_equals( testEl.properties.names.length, 2, 'length after adding a child' );
assert_equals( testEl.properties.names[0], 'foo', 'item 0 after adding a child' );
assert_equals( testEl.properties.names[1], 'bar', 'item 1 after adding a child' );
testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( testEl.properties.names.length, 2, 'foo length after adding a child with duplicated name' );
assert_equals( testEl.properties.names[0], 'foo', 'item 0 after adding a child with duplicated name' );
assert_equals( testEl.properties.names[1], 'bar', 'item 1 after adding a child with duplicated name' );
testEl.removeChild(testEl.lastChild);
assert_equals( testEl.properties.names.length, 1, 'length after removing a child' );
assert_equals( testEl.properties.names[0], 'foo', 'item 0 after removing a child' );
}, 'names must update when adding property elements');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
var DSL = testEl.properties.names;
assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
assert_equals( DSL[1], 'bar', 'item 1 (before test)' );
testEl.appendChild(testEl.firstChild);
assert_equals( DSL[0], 'bar', 'item 0 (after test)' );
assert_equals( DSL[1], 'foo', 'item 1 (after test)' );
}, 'names must update when re-ordering property elements');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
var DSL = testEl.properties.names;
assert_equals( DSL.length, 1, 'length (before test)' );
assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
testEl.lastChild.itemProp.toggle('bar');
assert_equals( DSL.length, 2, 'length after adding a token' );
assert_equals( DSL[0], 'foo', 'item 0 after adding a token' );
assert_equals( DSL[1], 'bar', 'item 1 after adding a token' );
testEl.lastChild.itemProp.add('foo');
assert_equals( DSL.length, 2, 'length after adding a duplicated token' );
assert_equals( DSL[0], 'foo', 'item 0 after adding a duplicated token' );
assert_equals( DSL[1], 'bar', 'item 1 after adding a duplicated token' );
testEl.lastChild.removeAttribute('itemprop');
assert_equals( DSL.length, 1, 'length after removing an attribute' );
assert_equals( DSL[0], 'foo', 'item 0 after removing an attribute' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div><div itemprop="foo"></div>');
DSL = testEl.properties.names;
assert_equals( DSL.length, 2, 'length (before second test)' );
assert_equals( DSL[0], 'foo', 'item 0 (before second test)' );
assert_equals( DSL[1], 'bar', 'item 1 (before second test)' );
testEl.firstChild.removeAttribute('itemprop');
assert_equals( DSL.length, 2, 'length after removing attribute of first item' );
assert_equals( DSL[0], 'bar', 'item 0 after removing attribute of first item' );
assert_equals( DSL[1], 'foo', 'item 1 after removing attribute of first item' );
testEl.firstChild.itemProp.add('foo');
assert_equals( DSL.length, 2, 'length after adding duplicated token to first item' );
assert_equals( DSL[0], 'foo', 'item 0 after adding duplicated token to first item' );
assert_equals( DSL[1], 'bar', 'item 1 after adding duplicated token to first item' );
testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo bar"></div>');
DSL = testEl.properties.names;
assert_equals( DSL.length, 2, 'length (before third test)' );
assert_equals( DSL[0], 'foo', 'item 0 (before third test)' );
assert_equals( DSL[1], 'bar', 'item 1 (before third test)' );
testEl.firstChild.itemProp.toggle('foo');
testEl.firstChild.itemProp.toggle('foo');
assert_equals( DSL.length, 2, 'length after swapping tokens' );
assert_equals( DSL[0], 'bar', 'item 0 after swapping tokens' );
assert_equals( DSL[1], 'foo', 'item 1 after swapping tokens' );
}, 'names must update when changing itemProp of children');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
var DSL = testEl.properties.names;
assert_equals( DSL.length, 0, 'length (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( DSL.length, 2, 'length after id is created' );
assert_equals( DSL[0], 'foo', 'item 0 after id is created' );
assert_equals( DSL[1], 'bar', 'item 1 after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( DSL.length, 0, 'length after removing an attribute' );
document.body.appendChild(parEl);
var step1length = DSL.length;
parEl.firstChild.id = 'id1';
var step2length = DSL.length;
var step2item0 = DSL[0];
var step2item1 = DSL[1];
parEl.firstChild.removeAttribute('id');
var step3length = DSL.length;
document.body.removeChild(parEl);
assert_equals( step1length, 0, 'length (before test) when appended to document' );
assert_equals( step2length, 2, 'length after id is created when appended to document' );
assert_equals( step2item0, 'foo', 'item 0 after id is created when appended to document' );
assert_equals( step2item1, 'bar', 'item 1 after id is created when appended to document' );
assert_equals( step3length, 0, 'length after removing an attribute when appended to document' );
}, 'names must update when changing id of referenced sibling when appended to document');
test(function () {
var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[1];
var DSL = testEl.properties.names;
assert_equals( DSL.length, 1, 'length (before test)' );
assert_equals( DSL[0], 'baz', 'item 0 (before test)' );
parEl.firstChild.id = 'id1';
assert_equals( DSL.length, 2, 'length after id is created' );
assert_equals( DSL[0], 'foo', 'item 0 after id is created' );
assert_equals( DSL[1], 'bar', 'item 1 after id is created' );
parEl.firstChild.removeAttribute('id');
assert_equals( DSL.length, 1, 'length after removing an attribute' );
assert_equals( DSL[0], 'baz', 'item 0 after removing an attribute' );
document.body.appendChild(parEl);
var step1length = DSL.length;
var step1item0 = DSL[0];
parEl.firstChild.id = 'id1';
var step2length = DSL.length;
var step2item0 = DSL[0];
var step2item1 = DSL[1];
parEl.firstChild.removeAttribute('id');
var step3length = DSL.length;
var step3item0 = DSL[0];
document.body.removeChild(parEl);
assert_equals( step1length, 1, 'length (before test)' );
assert_equals( step1item0, 'baz', 'item 0 (before test)' );
assert_equals( step2length, 2, 'length after id is created' );
assert_equals( step2item0, 'foo', 'item 0 after id is created' );
assert_equals( step2item1, 'bar', 'item 1 after id is created' );
assert_equals( step3length, 1, 'length after removing an attribute' );
assert_equals( step3item0, 'baz', 'item 0 after removing an attribute' );
}, 'names must update when changing duplicated id of referenced sibling');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
var testEl = parEl.childNodes[1];
var DSL = testEl.properties.names;
assert_equals( DSL.length, 0, 'length (before test)' );
testEl.itemRef.toggle('id1');
assert_equals( DSL.length, 1, 'length after itemref is changed' );
assert_equals( DSL[0], 'foo', 'item 0 after itemref is changed' );
testEl.removeAttribute('itemref');
assert_equals( DSL.length, 0, 'length after itemref is removed' );
assert_true( !DSL[0], 'item 0 after itemref is removed' );
document.body.appendChild(parEl);
var step1length = DSL.length;
testEl.itemRef.toggle('id1');
var step2length = DSL.length;
var step2item = DSL[0];
testEl.removeAttribute('itemref');
var step3length = DSL.length;
var step3item = DSL[0];
document.body.removeChild(parEl);
assert_equals( step1length, 0, 'length (before test)' );
assert_equals( step2length, 1, 'length after itemref is changed' );
assert_equals( step2item, 'foo', 'item 0 after itemref is changed' );
assert_equals( step3length, 0, 'length after itemref is removed' );
assert_true( !step3item, 'item 0 after itemref is removed' );
}, 'names must update when changing itemref to point to an element');
test(function () {
var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
var testEl = parEl.childNodes[1];
var DSL = testEl.properties.names;
assert_equals( DSL.length, 0, 'length (before test)' );
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( DSL.length, 1, 'length after a referenced element is added' );
assert_equals( DSL.item(0), 'foo', 'item 0 after a referenced element is added' ); //uses item just for the fun of it
parEl.firstChild.firstChild.itemProp.toggle('bar');
assert_equals( DSL.length, 2, 'length after a referenced itemprop is changed' );
assert_equals( DSL[0], 'bar', 'item 0 after a referenced element is added' );
assert_equals( DSL[1], 'foo', 'item 1 after a referenced element is added' );
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
assert_equals( DSL.length, 1, 'length after a referenced element is removed' );
assert_equals( DSL[0], 'foo', 'item 0 after a referenced element is removed' );
parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
testEl = parEl.childNodes[1];
DSL = testEl.properties.names;
document.body.appendChild(parEl);
var step1length = DSL.length;
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
var step2length = DSL.length;
var step2item0 = DSL.item(0); //uses item just for the fun of it
parEl.firstChild.firstChild.itemProp.toggle('bar');
var step3length = DSL.length;
var step3item0 = DSL[0];
var step3item1 = DSL[1];
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
var step4length = DSL.length;
var step4item0 = DSL[0];
document.body.removeChild(parEl);
assert_equals( step1length, 0, 'length (before test)' );
parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
assert_equals( step2length, 1, 'length after a referenced element is added' );
assert_equals( step2item0, 'foo', 'item 0 after a referenced element is added' ); //uses item just for the fun of it
parEl.firstChild.firstChild.itemProp.toggle('bar');
assert_equals( step3length, 2, 'length after a referenced itemprop is changed' );
assert_equals( step3item0, 'bar', 'item 0 after a referenced element is added' );
assert_equals( step3item1, 'foo', 'item 1 after a referenced element is added' );
parEl.firstChild.removeChild(parEl.firstChild.firstChild);
assert_equals( step4length, 1, 'length after a referenced element is removed' );
assert_equals( step4item0, 'foo', 'item 0 after a referenced element is removed' );
}, 'names must update when changing children of elements referenced through itemref');
test(function () {
var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="bar"></div></div>');
var testEl = parEl.childNodes[1];
var DSL = testEl.properties.names;
assert_equals( DSL.length, 2, 'length (before test)' );
assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
assert_equals( DSL[1], 'bar', 'item 1 (before test)' );
document.body.appendChild(testEl);
var step1length = DSL.length;
var step1prop0 = DSL[0];
var step1prop1 = DSL[1];
parEl.appendChild(testEl);
assert_equals( step1length, 1, 'length after changing parent' );
assert_equals( step1prop0, 'bar', 'item 0 after changing parent' );
assert_true( !step1prop1, 'item 1 after changing parent' );
assert_equals( DSL.length, 2, 'length after re-parenting' );
assert_equals( DSL[0], 'foo', 'item 0 after re-parenting' );
assert_equals( DSL[1], 'bar', 'item 1 after re-parenting' );
document.body.appendChild(parEl);
var step2length = DSL.length;
var step2prop0 = DSL[0];
var step2prop1 = DSL[1];
document.createElement('div').appendChild(testEl);
var step3length = DSL.length;
var step3prop0 = DSL[0];
var step3prop1 = DSL[1];
parEl.appendChild(testEl);
var step4length = DSL.length;
var step4prop0 = DSL[0];
var step4prop1 = DSL[1];
document.body.removeChild(parEl);
assert_equals( step2length, 2, 'length (before test) when appended to document' );
assert_equals( step2prop0, 'foo', 'item 0 (before test) when appended to document' );
assert_equals( step2prop1, 'bar', 'item 1 (before test) when appended to document' );
assert_equals( step3length, 1, 'length after changing parent when appended to document' );
assert_equals( step3prop0, 'bar', 'item 0 after changing parent when appended to document' );
assert_true( !step3prop1, 'item 1 after changing parent when appended to document' );
assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
assert_equals( step4prop0, 'foo', 'item 0 after re-parenting when appended to document' );
assert_equals( step4prop1, 'bar', 'item 1 after re-parenting when appended to document' );
}, 'names must update when appending elements with itemref to different parents');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
var DSL = testEl.properties.names;
assert_equals( DSL.length, 1, 'length (before test)' );
assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
testEl.firstChild.itemScope = true;
assert_equals( DSL.length, 0, 'length after setting itemscope' );
assert_true( !DSL[0], 'item 0 after setting itemscope' );
testEl.firstChild.removeAttribute('itemscope');
assert_equals( DSL.length, 1, 'length after removing itemscope attribute' );
assert_equals( DSL[0], 'foo', 'item 0 after removing itemscope attribute' );
}, 'names must update when changing itemscope of children');
/* potential bugs */
test(function () {
var parEl = makeEl('div',{},'<div id="id1"></div>');
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
parEl.appendChild(testEl);
testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
parEl.appendChild(makeEl('time',{itemprop:'bar',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
parEl.firstChild.appendChild(makeEl('div',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('madeuponthespot',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
var properties, PNLfoo, PNLbar, PNLbaz, fooValues, barValues, bazValues, allArrays, snapshot = [];
document.body.appendChild(parEl);
try {
properties = testEl.properties;
PNLfoo = properties.namedItem('foo');
PNLbar = properties.namedItem('bar');
PNLbaz = properties.namedItem('baz');
fooValues = PNLfoo.getValues();
barValues = PNLbar.getValues();
bazValues = PNLbaz.getValues();
allArrays = [properties,PNLfoo,PNLbar,PNLbaz,fooValues,barValues,bazValues];
for( var a = 0; a < allArrays.length; a++ ) {
snapshot[a] = [];
for( var b = 0; b < allArrays[a].length; b++ ) {
snapshot[a][b] = allArrays[a][b];
}
}
} catch(e) { /* need to clean up */ }
document.body.removeChild(parEl);
var c, d;
for( c = 0; c < allArrays.length; c++ ) {
for( d = 0; d < allArrays[c].length; d++ ) {
assert_equals( snapshot[c][d], allArrays[c][d], 'allArrays['+c+']['+d+']' );
}
}
var newArrays = [testEl.properties,testEl.properties.namedItem('foo'),testEl.properties.namedItem('bar'),testEl.properties.namedItem('baz'),testEl.properties.namedItem('foo').getValues(),testEl.properties.namedItem('bar').getValues(),testEl.properties.namedItem('baz').getValues()];
for( c = 0; c < newArrays.length; c++ ) {
for( d = 0; d < newArrays[c].length; d++ ) {
assert_equals( snapshot[c][d], newArrays[c][d], 'newArrays['+c+']['+d+']' );
}
}
}, 'collections must survive the parent\'s removal from the document');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'});
testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
testEl.appendChild(makeEl('time',{itemprop:'bar',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('div',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
testEl.appendChild(makeEl('madeuponthespot',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
var properties, PNLfoo, PNLbar, PNLbaz, fooValues, barValues, bazValues, allArrays, snapshot = [];
document.body.appendChild(testEl);
try {
properties = testEl.properties;
PNLfoo = properties.namedItem('foo');
PNLbar = properties.namedItem('bar');
PNLbaz = properties.namedItem('baz');
fooValues = PNLfoo.getValues();
barValues = PNLbar.getValues();
bazValues = PNLbaz.getValues();
allArrays = [properties,PNLfoo,PNLbar,PNLbaz,fooValues,barValues,bazValues];
for( var a = 0; a < allArrays.length; a++ ) {
snapshot[a] = [];
for( var b = 0; b < allArrays[a].length; b++ ) {
snapshot[a][b] = allArrays[a][b];
}
}
} catch(e) { /* need to clean up */ }
document.body.removeChild(testEl);
var c, d;
for( c = 0; c < allArrays.length; c++ ) {
for( d = 0; d < allArrays[c].length; d++ ) {
assert_equals( snapshot[c][d], allArrays[c][d], 'allArrays['+c+']['+d+']' );
}
}
var newArrays = [testEl.properties,testEl.properties.namedItem('foo'),testEl.properties.namedItem('bar'),testEl.properties.namedItem('baz'),testEl.properties.namedItem('foo').getValues(),testEl.properties.namedItem('bar').getValues(),testEl.properties.namedItem('baz').getValues()];
for( c = 0; c < newArrays.length; c++ ) {
for( d = 0; d < newArrays[c].length; d++ ) {
assert_equals( snapshot[c][d], newArrays[c][d], 'newArrays['+c+']['+d+']' );
}
}
}, 'collections must survive the item\'s removal from the document');
/* override_builtins */
test(function () {
//http://dev.w3.org/2006/webapi/WebIDL/#named-properties
//[OverrideBuiltins] is not declared for any of the properties, hence no overriding is allowed
var testEl = makeEl('div',{itemscope:'itemscope'});
var namedItem = testEl.properties.namedItem;
var item = testEl.properties.item;
var names = testEl.properties.names;
testEl.innerHTML = '<div itemprop="namedItem length item names"></div>';
assert_equals( testEl.properties['namedItem'], namedItem, 'namedItem' );
assert_equals( testEl.properties['length'], 1, 'length' );
assert_equals( testEl.properties['item'], item, 'item' );
assert_equals( testEl.properties['names'], names, 'names' );
}, 'itemprop names must not override builtin properties');
/* casting */
//when calling object[other_object], ECMAScript treats other_object as a named property so it casts it to a string using toString
//when looking up a named property, ECMAScript and WebIDL <http://dev.w3.org/2006/webapi/WebIDL/#named-properties> will prefer an array index property name
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2"></div><div itemprop="0"></div>');
assert_equals( testEl.properties.item('0'), testEl.properties.item(0), '0' );
assert_equals( testEl.properties.item('2'), testEl.properties.item(2), '2' );
}, 'properties.item(integerString) should cast to a number');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2"></div><div itemprop="0"></div>');
assert_equals( testEl.properties['0'], testEl.properties.item(0), '0' );
assert_equals( testEl.properties['2'], window.undefined, '2' );
}, 'properties[integerString] should act as a numeric index');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="0"></div>');
assert_equals( testEl.properties.namedItem(0), testEl.properties.namedItem('0'), '0' );
assert_true( testEl.properties.namedItem(0) instanceof PropertyNodeList , 'instanceof' );
}, 'properties.namedItem(integer) should cast to a string');
test(function () {
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2 foo"></div><div itemprop="0"></div>');
assert_equals( testEl.properties[{ toString: function(){return 'foo';}, valueOf: function(){return 1;} }][0], testEl.firstChild, 'foo' );
assert_equals( testEl.properties[{ toString: function(){return '0';}, valueOf: function(){return 1;} }], testEl.firstChild, '0' );
assert_equals( testEl.properties[{ toString: function(){return '2';}, valueOf: function(){return 0;} }], window.undefined, '2' );
}, 'properties[someObject] should cast toString before using whichever casting applies');
/* loops and evil itemref */
test(function () {
//This should have 1 property on each itemscope, pointing only to its direct child
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo"><div itemprop="bar"></div></div>');
assert_equals( testEl.properties.length, 1, 'outer length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
assert_true( !testEl.properties[1], 'outer properties[1]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
assert_true( !testEl.properties.names[1], 'outer names[1]' );
assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1]' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
}, 'simple nested itemscope');
test(function () {
//This should have 1 property on each itemscope, pointing only to its direct child
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'},'<div itemscope itemprop="foo" id="id1" itemref="id2"><div itemprop="bar" id="id2"></div></div>');
assert_equals( testEl.properties.length, 1, 'outer length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
assert_true( !testEl.properties[1], 'outer properties[1]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
assert_true( !testEl.properties.names[1], 'outer names[1]' );
assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1]' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 1, 'outer length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
assert_true( !testEl.properties[1], 'outer properties[1] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0] when appended to document' );
assert_equals( testEl.properties.names.length, 1, 'outer names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
assert_true( !testEl.properties.names[1], 'outer names[1] when appended to document' );
assert_equals( testEl.firstChild.properties.length, 1, 'inner length when appended to document' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
assert_true( !testEl.firstChild.properties[1], 'inner properties[1] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1] when appended to document' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length when appended to document' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
assert_true( !testEl.firstChild.properties.names[1], 'inner names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'simple nested itemscope with itemref');
test(function () {
//This should have 3 properties on the item; foo, bar and baz
var parEl = makeEl('div',{},'<div itemprop="foo" id="id2"></div><div itemscope itemref="id1 id2"><div itemprop="bar"></div></div><div itemprop="baz" id="id1"></div>');
var testEl = parEl.childNodes[1];
assert_equals( testEl.properties.length, 3, 'length' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0]' );
assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1]' );
assert_equals( testEl.properties[2], parEl.lastChild, 'properties[2]' );
assert_true( !testEl.properties[3], 'properties[3]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1]' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz.length' );
assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz[0]' );
assert_true( !testEl.properties.namedItem('baz')[1], 'baz[1]' );
assert_equals( testEl.properties.names.length, 3, 'names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'names[0]' );
assert_equals( testEl.properties.names[1], 'bar', 'names[1]' );
assert_equals( testEl.properties.names[2], 'baz', 'names[2]' );
assert_true( !testEl.properties.names[3], 'names[3]' );
document.body.appendChild(parEl);
try {
assert_equals( testEl.properties.length, 3, 'length when appended to document' );
assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] when appended to document' );
assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] when appended to document' );
assert_equals( testEl.properties[2], parEl.lastChild, 'properties[2] when appended to document' );
assert_true( !testEl.properties[3], 'properties[3] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz.length when appended to document' );
assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz[0] when appended to document' );
assert_true( !testEl.properties.namedItem('baz')[1], 'baz[1] when appended to document' );
assert_equals( testEl.properties.names.length, 3, 'names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'names[0] when appended to document' );
assert_equals( testEl.properties.names[1], 'bar', 'names[1] when appended to document' );
assert_equals( testEl.properties.names[2], 'baz', 'names[2] when appended to document' );
assert_true( !testEl.properties.names[3], 'names[3] when appended to document' );
} catch(e) {
document.body.removeChild(parEl);
throw (e);
}
document.body.removeChild(parEl);
}, 'simple sibling itemref');
test(function () {
//This should have no properties
var testEl = makeEl('div',{itemscope:'itemscope',id:'id1',itemref:'id1',itemprop:'foo'});
assert_equals( testEl.properties.length, 0, 'length' );
assert_true( !testEl.properties[0], 'properties[0]' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length' );
assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0]' );
assert_equals( testEl.properties.names.length, 0, 'names.length' );
assert_true( !testEl.properties.names[0], 'names[0]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 0, 'length when appended to document' );
assert_true( !testEl.properties[0], 'properties[0] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
assert_equals( testEl.properties.names.length, 0, 'names.length when appended to document' );
assert_true( !testEl.properties.names[0], 'names[0] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'itemref pointing to itself');
test(function () {
//This should have 1 property, pointing to the child
var testEl = makeEl('div',{itemscope:'itemscope',id:'id1',itemref:'id1',itemprop:'foo'},'<div itemprop="bar"></div>');
assert_equals( testEl.properties.length, 1, 'length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0]' );
assert_true( !testEl.properties[1], 'properties[1]' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length' );
assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0]' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1]' );
assert_equals( testEl.properties.names.length, 1, 'names.length' );
assert_equals( testEl.properties.names[0], 'bar', 'names[0]' );
assert_true( !testEl.properties.names[1], 'names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 1, 'length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] when appended to document' );
assert_true( !testEl.properties[1], 'properties[1] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
assert_equals( testEl.properties.names.length, 1, 'names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'bar', 'names[0] when appended to document' );
assert_true( !testEl.properties.names[1], 'names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'itemref pointing to itself with child');
test(function () {
//This should have 1 property on each itemscope, pointing only to its direct child
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo" id="id1" itemref="id1"><div itemprop="bar"></div></div>');
assert_equals( testEl.properties.length, 1, 'outer length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
assert_true( !testEl.properties[1], 'outer properties[1]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
assert_true( !testEl.properties.names[1], 'outer names[1]' );
assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1]' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 1, 'outer length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
assert_true( !testEl.properties[1], 'outer properties[1] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0] when appended to document' );
assert_equals( testEl.properties.names.length, 1, 'outer names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
assert_true( !testEl.properties.names[1], 'outer names[1] when appended to document' );
assert_equals( testEl.firstChild.properties.length, 1, 'inner length when appended to document' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
assert_true( !testEl.firstChild.properties[1], 'inner properties[1] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1] when appended to document' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length when appended to document' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
assert_true( !testEl.firstChild.properties.names[1], 'inner names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'nested itemref pointing to itself with child');
test(function () {
//Each itemscope has one property, pointing to the other one
var testEl = makeEl('div',{},'<div id="id1" itemprop="foo" itemscope itemref="id2"></div><div id="id2" itemprop="bar" itemscope itemref="id1"></div>');
assert_equals( testEl.firstChild.properties.length, 1, 'id1 length' );
assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0]' );
assert_true( !testEl.firstChild.properties[1], 'id1 properties[1]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1]' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0]' );
assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1]' );
assert_equals( testEl.lastChild.properties.length, 1, 'id2 length' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0]' );
assert_true( !testEl.lastChild.properties[1], 'id2 properties[1]' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length' );
assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0]' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1]' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0]' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length' );
assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0]' );
assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.firstChild.properties.length, 1, 'id1 length when appended to document' );
assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0] when appended to document' );
assert_true( !testEl.firstChild.properties[1], 'id1 properties[1] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1] when appended to document' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length when appended to document' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0] when appended to document' );
assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1] when appended to document' );
assert_equals( testEl.lastChild.properties.length, 1, 'id2 length when appended to document' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0] when appended to document' );
assert_true( !testEl.lastChild.properties[1], 'id2 properties[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0] when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0] when appended to document' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length when appended to document' );
assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0] when appended to document' );
assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'mutually referencing siblings');
test(function () {
//Root has 2 properties, foo and bar
//Each itemscope has one property, pointing to the other one
var testEl = makeEl('div',{itemscope:'itemscope'},'<div id="id1" itemprop="foo" itemscope itemref="id2"></div><div id="id2" itemprop="bar" itemscope itemref="id1"></div>');
assert_equals( testEl.properties.length, 2, 'root length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0]' );
assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1]' );
assert_true( !testEl.properties[2], 'root properties[2]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0]' );
assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1]' );
assert_equals( testEl.properties.names.length, 2, 'root names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'root names[0]' );
assert_equals( testEl.properties.names[1], 'bar', 'root names[1]' );
assert_true( !testEl.properties.names[2], 'root names[2]' );
assert_equals( testEl.firstChild.properties.length, 1, 'id1 length' );
assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0]' );
assert_true( !testEl.firstChild.properties[1], 'id1 properties[1]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1]' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0]' );
assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1]' );
assert_equals( testEl.lastChild.properties.length, 1, 'id2 length' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0]' );
assert_true( !testEl.lastChild.properties[1], 'id2 properties[1]' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length' );
assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0]' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1]' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0]' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length' );
assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0]' );
assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 2, 'root length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0] when appended to document' );
assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1] when appended to document' );
assert_true( !testEl.properties[2], 'root properties[2] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length when appended to document' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0] when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1] when appended to document' );
assert_equals( testEl.properties.names.length, 2, 'root names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'root names[0] when appended to document' );
assert_equals( testEl.properties.names[1], 'bar', 'root names[1] when appended to document' );
assert_true( !testEl.properties.names[2], 'root names[2] when appended to document' );
assert_equals( testEl.firstChild.properties.length, 1, 'id1 length when appended to document' );
assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0] when appended to document' );
assert_true( !testEl.firstChild.properties[1], 'id1 properties[1] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1] when appended to document' );
assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length when appended to document' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0] when appended to document' );
assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1] when appended to document' );
assert_equals( testEl.lastChild.properties.length, 1, 'id2 length when appended to document' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0] when appended to document' );
assert_true( !testEl.lastChild.properties[1], 'id2 properties[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0] when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0] when appended to document' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length when appended to document' );
assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0] when appended to document' );
assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'mutually referencing siblings with item parent');
test(function () {
//Root has two properties, foo and bar
//Bar has two properties, baz and qux
//Qux has one property, bar
var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div id="id1" itemprop="bar" itemscope><div itemprop="baz"></div><div itemprop="qux" itemscope itemref="id1"></div></div>');
assert_equals( testEl.properties.length, 2, 'root length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0]' );
assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1]' );
assert_true( !testEl.properties[2], 'root properties[2]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0]' );
assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1]' );
assert_equals( testEl.properties.namedItem('baz').length, 0, 'root baz.length' );
assert_true( !testEl.properties.namedItem('baz')[0], 'root baz[0]' );
assert_equals( testEl.properties.namedItem('qux').length, 0, 'root qux.length' );
assert_true( !testEl.properties.namedItem('qux')[0], 'root qux[0]' );
assert_equals( testEl.properties.names.length, 2, 'root names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'root names[0]' );
assert_equals( testEl.properties.names[1], 'bar', 'root names[1]' );
assert_true( !testEl.properties.names[2], 'root names[2]' );
assert_equals( testEl.lastChild.properties.length, 2, 'bar length' );
assert_equals( testEl.lastChild.properties[0], testEl.lastChild.firstChild, 'bar properties[0]' );
assert_equals( testEl.lastChild.properties[1], testEl.lastChild.lastChild, 'bar properties[1]' );
assert_true( !testEl.lastChild.properties[2], 'bar properties[2]' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'bar foo.length' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'bar foo[0]' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'bar bar.length' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'bar bar[0]' );
assert_equals( testEl.lastChild.properties.namedItem('baz').length, 1, 'bar baz.length' );
assert_equals( testEl.lastChild.properties.namedItem('baz')[0], testEl.lastChild.firstChild, 'bar baz[0]' );
assert_true( !testEl.lastChild.properties.namedItem('baz')[1], 'bar baz[1]' );
assert_equals( testEl.lastChild.properties.namedItem('qux').length, 1, 'bar qux.length' );
assert_equals( testEl.lastChild.properties.namedItem('qux')[0], testEl.lastChild.lastChild, 'bar qux[0]' );
assert_true( !testEl.lastChild.properties.namedItem('qux')[1], 'bar qux[1]' );
assert_equals( testEl.lastChild.properties.names.length, 2, 'bar names.length' );
assert_equals( testEl.lastChild.properties.names[0], 'baz', 'bar names[0]' );
assert_equals( testEl.lastChild.properties.names[1], 'qux', 'bar names[1]' );
assert_true( !testEl.lastChild.properties.names[2], 'bar names[2]' );
assert_equals( testEl.lastChild.lastChild.properties.length, 1, 'qux length' );
assert_equals( testEl.lastChild.lastChild.properties[0], testEl.lastChild, 'qux properties[0]' );
assert_true( !testEl.lastChild.lastChild.properties[1], 'qux properties[1]' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('foo').length, 0, 'qux foo.length' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('foo')[0], 'qux foo[0]' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar').length, 1, 'qux bar.length' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar')[0], testEl.lastChild, 'qux bar[0]' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('bar')[1], 'qux bar[1]' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('baz').length, 0, 'qux baz.length' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('baz')[0], 'qux baz[0]' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('qux').length, 0, 'qux qux.length' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('qux')[0], 'qux qux[0]' );
assert_equals( testEl.lastChild.lastChild.properties.names.length, 1, 'qux names.length' );
assert_equals( testEl.lastChild.lastChild.properties.names[0], 'bar', 'qux names[0]' );
assert_true( !testEl.lastChild.lastChild.properties.names[1], 'qux names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 2, 'root length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0] when appended to document' );
assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1] when appended to document' );
assert_true( !testEl.properties[2], 'root properties[2] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length when appended to document' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0] when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1] when appended to document' );
assert_equals( testEl.properties.namedItem('baz').length, 0, 'root baz.length when appended to document' );
assert_true( !testEl.properties.namedItem('baz')[0], 'root baz[0] when appended to document' );
assert_equals( testEl.properties.namedItem('qux').length, 0, 'root qux.length when appended to document' );
assert_true( !testEl.properties.namedItem('qux')[0], 'root qux[0] when appended to document' );
assert_equals( testEl.properties.names.length, 2, 'root names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'root names[0] when appended to document' );
assert_equals( testEl.properties.names[1], 'bar', 'root names[1] when appended to document' );
assert_true( !testEl.properties.names[2], 'root names[2] when appended to document' );
assert_equals( testEl.lastChild.properties.length, 2, 'bar length when appended to document' );
assert_equals( testEl.lastChild.properties[0], testEl.lastChild.firstChild, 'bar properties[0] when appended to document' );
assert_equals( testEl.lastChild.properties[1], testEl.lastChild.lastChild, 'bar properties[1] when appended to document' );
assert_true( !testEl.lastChild.properties[2], 'bar properties[2] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'bar foo.length when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'bar foo[0] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'bar bar.length when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'bar bar[0] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('baz').length, 1, 'bar baz.length when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('baz')[0], testEl.lastChild.firstChild, 'bar baz[0] when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('baz')[1], 'bar baz[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('qux').length, 1, 'bar qux.length when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('qux')[0], testEl.lastChild.lastChild, 'bar qux[0] when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('qux')[1], 'bar qux[1] when appended to document' );
assert_equals( testEl.lastChild.properties.names.length, 2, 'bar names.length when appended to document' );
assert_equals( testEl.lastChild.properties.names[0], 'baz', 'bar names[0] when appended to document' );
assert_equals( testEl.lastChild.properties.names[1], 'qux', 'bar names[1] when appended to document' );
assert_true( !testEl.lastChild.properties.names[2], 'bar names[2] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.length, 1, 'qux length when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties[0], testEl.lastChild, 'qux properties[0] when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties[1], 'qux properties[1] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('foo').length, 0, 'qux foo.length when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('foo')[0], 'qux foo[0] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar').length, 1, 'qux bar.length when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar')[0], testEl.lastChild, 'qux bar[0] when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('bar')[1], 'qux bar[1] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('baz').length, 0, 'qux baz.length when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('baz')[0], 'qux baz[0] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.namedItem('qux').length, 0, 'qux qux.length when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties.namedItem('qux')[0], 'qux qux[0] when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.names.length, 1, 'qux names.length when appended to document' );
assert_equals( testEl.lastChild.lastChild.properties.names[0], 'bar', 'qux names[0] when appended to document' );
assert_true( !testEl.lastChild.lastChild.properties.names[1], 'qux names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'itemref referencing parent item');
test(function () {
//foo has one property, bar
var testEl = makeEl('div',{id:'id1'},'<div itemprop="bar"></div><div itemscope itemref="id1" itemprop="foo"></div>');
assert_equals( testEl.lastChild.properties.length, 1, 'length' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'properties[0]' );
assert_true( !testEl.lastChild.properties[1], 'properties[1]' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'foo.length' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'foo[0]' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 1, 'bar.length' );
assert_equals( testEl.lastChild.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[1], 'bar[1]' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'names.length' );
assert_equals( testEl.lastChild.properties.names[0], 'bar', 'names[0]' );
assert_true( !testEl.lastChild.properties.names[1], 'names[1]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.lastChild.properties.length, 1, 'length when appended to document' );
assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'properties[0] when appended to document' );
assert_true( !testEl.lastChild.properties[1], 'properties[1] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
assert_equals( testEl.lastChild.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
assert_true( !testEl.lastChild.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
assert_equals( testEl.lastChild.properties.names.length, 1, 'names.length when appended to document' );
assert_equals( testEl.lastChild.properties.names[0], 'bar', 'names[0] when appended to document' );
assert_true( !testEl.lastChild.properties.names[1], 'names[1] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'itemref referencing parent without itemscope');
test(function () {
var testDiv = makeEl('div', {itemprop:'bar', id:'foo'}, '');
var testSpan = makeEl('span', {itemscope:'itemscope', itemref: 'foo', id: 'foo'}, '');
document.body.appendChild(testDiv);
document.body.appendChild(testSpan);
assert_equals(testSpan.properties.length, 1, 'has one property');
assert_equals(testSpan.properties[0], testDiv, 'has first property');
assert_equals(testSpan.properties.item(0), testDiv, 'has first property');
assert_equals(testSpan.properties.namedItem('bar').length, 1, 'has 1 foo property');
assert_equals(testSpan.properties.namedItem('bar').item(0), testDiv, 'div is foo property');
assert_equals(testSpan.properties.names.length, 1, 'only has one property');
document.body.removeChild(testDiv);
document.body.removeChild(testSpan);
}, 'itemref referencing element with same id');
test(function () {
//Root has three properties, foo, bar and baz
//Foo has two properties, bar and baz
var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'},'<div itemscope itemprop="foo"><div itemprop="bar" id="id1"><div itemprop="baz"></div></div></div>');
assert_equals( testEl.properties.length, 3, 'outer length' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
assert_equals( testEl.properties[1], testEl.firstChild.firstChild, 'outer properties[1]' );
assert_equals( testEl.properties[2], testEl.firstChild.firstChild.firstChild, 'outer properties[2]' );
assert_true( !testEl.properties[3], 'outer properties[3]' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'outer bar.length' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'outer bar[0]' );
assert_true( !testEl.properties.namedItem('bar')[1], 'outer bar[1]' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'outer baz.length' );
assert_equals( testEl.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'outer baz[0]' );
assert_true( !testEl.properties.namedItem('baz')[1], 'outer baz[1]' );
assert_equals( testEl.properties.names.length, 3, 'outer names.length' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
assert_equals( testEl.properties.names[1], 'bar', 'outer names[1]' );
assert_equals( testEl.properties.names[2], 'baz', 'outer names[2]' );
assert_true( !testEl.properties.names[3], 'outer names[3]' );
assert_equals( testEl.firstChild.properties.length, 2, 'inner length' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
assert_equals( testEl.firstChild.properties[1], testEl.firstChild.firstChild.firstChild, 'inner properties[1]' );
assert_true( !testEl.firstChild.properties[2], 'inner properties[2]' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1]' );
assert_equals( testEl.firstChild.properties.namedItem('baz').length, 1, 'inner baz.length' );
assert_equals( testEl.firstChild.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'inner baz[0]' );
assert_true( !testEl.firstChild.properties.namedItem('baz')[1], 'inner baz[1]' );
assert_equals( testEl.firstChild.properties.names.length, 2, 'inner names.length' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
assert_equals( testEl.firstChild.properties.names[1], 'baz', 'inner names[1]' );
assert_true( !testEl.firstChild.properties.names[2], 'inner names[2]' );
document.body.appendChild(testEl);
try {
assert_equals( testEl.properties.length, 3, 'outer length when appended to document' );
assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
assert_equals( testEl.properties[1], testEl.firstChild.firstChild, 'outer properties[1] when appended to document' );
assert_equals( testEl.properties[2], testEl.firstChild.firstChild.firstChild, 'outer properties[2] when appended to document' );
assert_true( !testEl.properties[3], 'outer properties[3] when appended to document' );
assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
assert_equals( testEl.properties.namedItem('bar').length, 1, 'outer bar.length when appended to document' );
assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'outer bar[0] when appended to document' );
assert_true( !testEl.properties.namedItem('bar')[1], 'outer bar[1] when appended to document' );
assert_equals( testEl.properties.namedItem('baz').length, 1, 'outer baz.length when appended to document' );
assert_equals( testEl.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'outer baz[0] when appended to document' );
assert_true( !testEl.properties.namedItem('baz')[1], 'outer baz[1] when appended to document' );
assert_equals( testEl.properties.names.length, 3, 'outer names.length when appended to document' );
assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
assert_equals( testEl.properties.names[1], 'bar', 'outer names[1] when appended to document' );
assert_equals( testEl.properties.names[2], 'baz', 'outer names[2] when appended to document' );
assert_true( !testEl.properties.names[3], 'outer names[3] when appended to document' );
assert_equals( testEl.firstChild.properties.length, 2, 'inner length when appended to document' );
assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
assert_equals( testEl.firstChild.properties[1], testEl.firstChild.firstChild.firstChild, 'inner properties[1] when appended to document' );
assert_true( !testEl.firstChild.properties[2], 'inner properties[2] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1] when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('baz').length, 1, 'inner baz.length when appended to document' );
assert_equals( testEl.firstChild.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'inner baz[0] when appended to document' );
assert_true( !testEl.firstChild.properties.namedItem('baz')[1], 'inner baz[1] when appended to document' );
assert_equals( testEl.firstChild.properties.names.length, 2, 'inner names.length when appended to document' );
assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
assert_equals( testEl.firstChild.properties.names[1], 'baz', 'inner names[1] when appended to document' );
assert_true( !testEl.firstChild.properties.names[2], 'inner names[2] when appended to document' );
} catch(e) {
document.body.removeChild(testEl);
throw (e);
}
document.body.removeChild(testEl);
}, 'itemref pointing to child of nested itemscope');
</script>
</body>
</html>