dom/imptests/html/microdata/microdata-dom-api/test_001.html

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 <!doctype html>
     2 <html>
     3 	<head>
     4 		<meta charset="UTF-8">
     5 		<title>Microdata tests</title>
     6 		<script type="text/javascript" src="/resources/testharness.js"></script>
     7 		<script type="text/javascript" src="/resources/testharnessreport.js"></script>
     8 		<link rel="help" href="http://dev.w3.org/html5/md/#microdata-dom-api">
     9 		<link rel="help" href="http://dev.w3.org/html5/md/#encoding-microdata">
    10 	</head>
    11 	<body>
    12 		<noscript><p>Enable JavaScript and reload</p></noscript>
    13 		<div id="log">Running test...</div>
    14 		<div itemscope itemtype="http://example.com/bar data:text/plain, http://example.com/foo" id="one"></div>
    15 		<div itemscope itemtype="http://example.com/bar" id="two"></div>
    16 		<div itemscope itemtype="http://example.com/foo http://example.com/bar" id="three">
    17 			<div itemscope itemtype="http://example.com/bar data:text/plain," id="four"></div>
    18 		</div>
    19 		<div itemscope id="five"></div>
    20 		<script type="text/javascript">
    21 /* All tests are stand-alone.
    22 To reduce this testsuite to show only a single desired test,
    23 simply remove all test(...) blocks before and after it. */
    25 function makeEl(eltype,props,contents) {
    26 	var elem = document.createElement(eltype);
    27 	for( var i in props ) {
    28 		//just in case the framework extends object...
    29 		if( props.hasOwnProperty(i) ) {
    30 			elem.setAttribute(i,props[i]);
    31 		}
    32 	}
    33 	if( contents ) {
    34 		elem.innerHTML = contents;
    35 	}
    36 	return elem;
    37 }
    39 /* getItem tests */
    40 test(function () {
    41 	assert_true( !!document.getItems );
    42 }, 'document.getItems must exist');
    43 test(function () {
    44 	assert_true( document.getItems() instanceof NodeList, 'instanceof test' );
    45 	NodeList.prototype.customProperty = true;
    46 	assert_true( document.getItems().customProperty, 'inheritance test' );
    47 }, 'document.getItems must return a NodeList');
    48 test(function () {
    49 	assert_equals( document.getItems().length, 5 );
    50 }, 'document.getItems must locate the correct number of items');
    51 test(function () {
    52 	var nlist = document.getItems();
    53 	var foo = makeEl('div',{itemscope:'itemscope'});
    54 	document.body.appendChild(foo);
    55 	var templength = nlist.length;
    56 	document.body.removeChild(foo);
    57 	assert_equals( templength, 6 );
    58 	assert_equals( nlist.length, 5 );
    59 }, 'document.getItems must return a live NodeList');
    60 test(function () {
    61 	var nlist = document.getItems();
    62 	document.getElementById('one').removeAttribute('itemscope');
    63 	var templength = nlist.length;
    64 	document.getElementById('one').setAttribute('itemscope','itemscope');
    65 	assert_equals( templength, 4 );
    66 	assert_equals( nlist.length, 5 );
    67 }, 'live NodeList must notice when itemscope changes');
    68 test(function () {
    69 	document.getElementById('one').removeAttribute('itemscope');
    70 	var templength = document.getItems().length;
    71 	document.getElementById('one').setAttribute('itemscope','itemscope');
    72 	assert_equals( templength, 4 );
    73 	assert_equals( document.getItems().length, 5 );
    74 }, 'next request must notice when itemscope changes');
    75 test(function () {
    76 	assert_equals( document.getItems('http://example.com/').length, 0, 'http://example.com/' );
    77 	assert_equals( document.getItems('example').length, 0, 'example' );
    78 	assert_equals( document.getItems('http://example.com/foo').length, 2, 'http://example.com/foo' );
    79 	assert_equals( document.getItems('http://example.com/bar').length, 4, 'http://example.com/bar' );
    80 	assert_equals( document.getItems('data:text/plain,').length, 2, 'data:text/plain,' );
    81 }, 'document.getItems must locate the right number of items for each itemtype');
    82 test(function () {
    83 	assert_equals( document.getItems('http://example.com/Foo').length, 0, 'http://example.com/Foo' );
    84 	assert_equals( document.getItems('HTTP://example.com/foo').length, 0, 'HTTP://example.com/foo' );
    85 }, 'document.getItems must be case sensitive');
    86 test(function () {
    87 	var nlist = document.getItems('http://example.com/foo');
    88 	var foo = makeEl('div',{itemscope:'itemscope',itemtype:'http://example.com/foo'});
    89 	document.body.appendChild(foo);
    90 	var templength = nlist.length;
    91 	document.body.removeChild(foo);
    92 	assert_equals( templength, 3 );
    93 	assert_equals( nlist.length, 2 );
    94 }, 'document.getItems must return a live NodeList when using URLs');
    95 test(function () {
    96 	var nlist = document.getItems('http://example.com/foo');
    97 	document.getElementById('one').removeAttribute('itemtype');
    98 	var templength = nlist.length;
    99 	document.getElementById('one').setAttribute('itemtype','http://example.com/bar data:text/plain, http://example.com/foo');
   100 	assert_equals( templength, 1 );
   101 	assert_equals( nlist.length, 2 );
   102 }, 'live NodeList must notice when itemtype changes');
   103 test(function () {
   104 	document.getElementById('one').removeAttribute('itemtype');
   105 	var templength = document.getItems('http://example.com/foo').length;
   106 	document.getElementById('one').setAttribute('itemtype','http://example.com/bar data:text/plain, http://example.com/foo');
   107 	assert_equals( templength, 1 );
   108 	assert_equals( document.getItems('http://example.com/foo').length, 2 );
   109 }, 'next request must notice when itemtype changes');
   110 test(function () {
   111         assert_equals( document.getItems('http://example.com/foo data:text/plain,').length, 1, 'basic spaces' );
   112 	assert_equals( document.getItems('  http://example.com/foo  data:text/plain,  ').length, 1, 'extraneous spaces' );
   113 }, 'document.getItems must locate items when parameters are separated by spaces');
   114 test(function () {
   115 	assert_equals( document.getItems('http://example.com/foo data:text/plain, http://example.com/foo').length, 1 );
   116 }, 'document.getItems must ignore duplicated tokens');
   117 test(function () {
   118 	var testitems = document.getItems('http://example.com/bar');
   119 	assert_equals( testitems[0].id, 'one' );
   120 	assert_equals( testitems[1].id, 'two' );
   121 	assert_equals( testitems[2].id, 'three' );
   122 	assert_equals( testitems[3].id, 'four' );
   123 }, 'document.getItems NodeList must be in source tree order');
   124 test(function () {
   125 	assert_true( document.getItems('http://example.com/abc') != document.getItems('http://example.com/def'), 'different tokens' );
   126 	assert_true( document.getItems() != document.getItems(' '), 'no tokens' );
   127 }, 'document.getItems must not return the same NodeList for different parameters');
   128 test(function () {
   129 	assert_equals( document.getItems('').length, 5, 'empty string' );
   130 	assert_equals( document.getItems('  ').length, 5, 'string with spaces' );
   131 }, 'document.getItems must treat no tokens as no parameter');
   132 //removed due to disputed Web compatibility of casting null with DOM methods
   133 /*
   134 test(function () {
   135 	assert_equals( document.getItems(null).length, 0, 'null' );
   136 	assert_equals( document.getItems(window.undefined).length, 0, 'undefined' );
   137 }, 'document.getItems must cast null and undefined to strings');
   138 */
   139 test(function () {
   140 	var foo = makeEl('div',{itemtype:'http://example.com/foo'});
   141 	document.body.appendChild(foo);
   142 	var templength = document.getItems('http://example.com/foo').length;
   143 	document.body.removeChild(foo);
   144 	assert_equals( templength, 2 );
   145 }, 'document.getItems must not find items with itemtype but not itemscope');
   146 test(function () {
   147 	var foo = makeEl('div',{itemscope:'itemscope',itemtype:'baz'}),
   148 	    bar = makeEl('div',{itemscope:'itemscope',itemtype:location.href.replace(/\/[^\/]*$/,'/baz')});
   149 	document.body.appendChild(foo);
   150 	document.body.appendChild(bar);
   151 	var unrezlength = document.getItems('baz').length;
   152 	var rezlength = document.getItems(location.href.replace(/\/[^\/]*$/,'/baz')).length;
   153 	document.body.removeChild(foo);
   154 	document.body.removeChild(bar);
   155 	assert_equals( unrezlength, 1, 'unresolved URL' );
   156 	assert_equals( rezlength, 1, 'resolved URL' );
   157 }, 'document.getItems and itemtype must not resolve URLs');
   158 test(function () {
   159 	document.getElementById('one').setAttribute('itemprop','test');
   160 	document.getElementById('four').setAttribute('itemprop','test');
   161 	var templength = document.getItems().length;
   162 	document.getElementById('one').removeAttribute('itemprop');
   163 	document.getElementById('four').removeAttribute('itemprop');
   164 	assert_equals( templength, 3 );
   165 }, 'document.getItems must not see items that have the itemprop attribute set');
   167 /* itemScope property tests */
   168 test(function () {
   169 	assert_true(makeEl('div',{itemscope:'itemscope'}).itemScope);
   170 	assert_false(makeEl('div',{}).itemScope);
   171 }, 'the itemscope attribute must be reflected by the .itemScope property');
   172 test(function () {
   173 	assert_equals( typeof makeEl('div',{itemscope:'itemscope'}).itemScope, 'boolean', 'attribute exists' );
   174 	assert_equals( typeof makeEl('div',{}).itemScope, 'boolean', 'attribute does not exist' );
   175 }, 'the itemScope property must be boolean');
   176 test(function () {
   177 	var testEl = makeEl('div',{});
   178 	testEl.itemScope = true;
   179 	assert_true(testEl.itemScope,'writing true');
   180 	testEl.itemScope = false;
   181 	assert_false(testEl.itemScope,'writing false');
   182 }, 'the itemScope property must be read/write');
   183 test(function () {
   184 	var testEl = makeEl('div',{});
   185 	testEl.itemScope = true;
   186 	assert_true(testEl.hasAttribute('itemscope'),'writing true');
   187 	testEl.itemScope = false;
   188 	assert_false(testEl.hasAttribute('itemscope'),'writing false');
   189 }, 'writing to the itemScope property must toggle existence of the itemscope content attribute');
   190 test(function () {
   191 	var testEl = makeEl('div',{});
   192 	document.body.appendChild(testEl);
   193 	var numAppend = document.getItems().length;
   194 	testEl.itemScope = true;
   195 	var numTrue = document.getItems().length;
   196 	testEl.itemScope = false;
   197 	var numFalse = document.getItems().length;
   198 	document.body.removeChild(testEl);
   199 	assert_equals(numAppend,5,'after appending the new item');
   200 	assert_equals(numTrue,6,'after setting the property to true');
   201 	assert_equals(numFalse,5,'after setting the property to false');
   202 }, 'writing to the itemScope property must affect whether the element is returned by getItems');
   203 test(function () {
   204 	var testEl = makeEl('div',{}), nlist = document.getItems();
   205 	document.body.appendChild(testEl);
   206 	var numAppend = nlist.length;
   207 	testEl.itemScope = true;
   208 	var numTrue = nlist.length;
   209 	testEl.itemScope = false;
   210 	var numFalse = nlist.length;
   211 	document.body.removeChild(testEl);
   212 	assert_equals(numAppend,5,'after appending the new item');
   213 	assert_equals(numTrue,6,'after setting the property to true');
   214 	assert_equals(numFalse,5,'after setting the property to false');
   215 }, 'writing to the itemScope property must affect membership of live NodeLists');
   217 /* itemType property tests (properties collection tests are done later) */
   218 test(function () {
   219 	assert_equals(makeEl('div',{}).itemType.toString(),'','no attribute');
   220 	assert_equals(makeEl('div',{itemtype:' foo  bar '}).itemType.toString(),' foo  bar ','with simple tokens');
   221 	var testEl = makeEl('div',{itemtype:'foo'});
   222 	testEl.removeAttribute('itemtype');
   223 	assert_equals(testEl.itemType.toString(),'','removed attribute');
   224 }, 'the itemType attribute must be reflected by the .itemRef property');
   225 test(function () {
   226 	assert_equals( typeof makeEl('div',{}).itemType, 'object' );
   227 }, 'the itemType property must be an object');
   228 test(function () {
   229 	assert_true( makeEl('div',{}).itemType instanceof DOMTokenList, 'instanceof test' );
   230 	DOMTokenList.prototype.customProperty = true;
   231 	assert_true( makeEl('div',{}).itemType.customProperty, 'inheritance test' );
   232 }, 'the itemType property must implement DOMTokenList');
   233 test(function () {
   234 	var testEl = makeEl('div',{});
   235 	assert_equals( testEl.itemType, testEl.itemType );
   236 }, 'the itemType property must always reference the same object');
   237 test(function () {
   238 	assert_equals( makeEl('div',{itemtype:'test test'}).itemType.length, 2, 'duplicates in initial string should be preserved' );
   239 	assert_equals( makeEl('div',{itemtype:'test test'}).itemType.item(0), 'test' );
   240 	assert_true( makeEl('div',{itemtype:'test test'}).itemType.contains('test') );
   241 }, 'itemType must be correct for an element that has itemtype tokens');
   242 test(function () {
   243 	assert_equals( makeEl('div',{itemtype:' '}).itemType.length, 0 );
   244 }, 'itemType.length must be 0 for an element that has no tokens');
   245 test(function () {
   246 	assert_false( makeEl('div',{itemtype:' '}).itemType.contains('foo') );
   247 }, 'itemType must not contain an undefined class');
   248 test(function () {
   249 	assert_equals( makeEl('div',{itemtype:' '}).itemType.item(0), null );
   250 }, 'itemType.item() must return null for out-of-range index');
   251 test(function () {
   252 	assert_equals( makeEl('div',{itemtype:' '}).itemType.item(-1), null );
   253 }, 'itemType.item() must return null for negative index');
   254 test(function () {
   255 	/* the normative part of the spec states that:
   256 	"unless the length is zero, in which case there are no supported property indices"
   257 	...
   258 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   259 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   260 	assert_equals( makeEl('div',{itemtype:' '}).itemType[0], window.undefined );
   261 }, 'itemType[index] must be undefined for out-of-range index');
   262 test(function () {
   263 	assert_equals( makeEl('div',{itemtype:' '}).itemType[-1], window.undefined );
   264 }, 'itemType[index] must be undefined for negative index');
   265 test(function () {
   266 	assert_equals( makeEl('div',{itemType:' '}).itemType.toString(), ' ' );
   267 }, 'empty itemType should stringify to contain the attribute\'s whitespace');
   268 test(function () {
   269 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.contains(''); } );
   270 }, 'itemType.contains(empty_string) must throw a SYNTAX_ERR');
   271 test(function () {
   272 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.add(''); } );
   273 }, 'itemType.add(empty_string) must throw a SYNTAX_ERR');
   274 test(function () {
   275 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.remove(''); } );
   276 }, 'itemType.remove(empty_string) must throw a SYNTAX_ERR');
   277 test(function () {
   278 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemtype:' '}).itemType.toggle(''); } );
   279 }, 'itemType.toggle(empty_string) must throw a SYNTAX_ERR');
   280 test(function () {
   281 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.contains('a b'); } );
   282 }, 'itemType.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   283 test(function () {
   284 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.add('a b'); } );
   285 }, 'itemType.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   286 test(function () {
   287 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.remove('a b'); } );
   288 }, 'itemType.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   289 test(function () {
   290 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemtype:' '}).itemType.toggle('a b'); } );
   291 }, 'itemType.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   292 test(function () {
   293 	var testEl = makeEl('div',{itemtype:'foo'});
   294 	assert_true( testEl.itemType.contains('foo'), 'before change' );
   295 	testEl.setAttribute('itemtype','bar');
   296 	assert_true( testEl.itemType.contains('bar'), 'after change' );
   297 	assert_false( testEl.itemType.contains('foo'), 'after change' );
   298 }, 'itemType.contains must update when the underlying attribute is changed');
   299 test(function () {
   300 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('FOO') );
   301 }, 'itemType.contains must be case sensitive');
   302 test(function () {
   303 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo.') );
   304 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo)') );
   305 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo\'') );
   306 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo$') );
   307 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo~') );
   308 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo?') );
   309 	assert_false( makeEl('div',{itemtype:'foo'}).itemType.contains('foo\\') );
   310 }, 'itemType.contains must not match when punctuation characters are added');
   311 test(function () {
   312 	var elem = makeEl('div',{itemtype:'foo'});
   313 	elem.itemType.add('FOO');
   314 	assert_true( elem.itemType.contains('foo') );
   315 }, 'itemType.add must not remove existing tokens');
   316 test(function () {
   317 	assert_true( makeEl('div',{itemtype:'foo FOO'}).itemType.contains('FOO') );
   318 }, 'itemType.contains case sensitivity must match a case-specific string');
   319 test(function () {
   320 	assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType.length, 2 );
   321 }, 'itemType.length must correctly reflect the number of tokens');
   322 test(function () {
   323 	assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType.item(0), 'foo' );
   324 }, 'itemType.item(0) must return the first token');
   325 test(function () {
   326 	var elem = makeEl('div',{itemtype:'foo'});
   327 	elem.itemType.add('FOO');
   328 	assert_equals( elem.itemType.item(1), 'FOO' );
   329 }, 'itemType.item must return case-sensitive strings and preserve token order');
   330 test(function () {
   331 	assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[0], 'foo' );
   332 }, 'itemType[0] must return the first token');
   333 test(function () {
   334 	assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[1], 'FOO' );
   335 }, 'itemType[index] must return case-sensitive strings and preserve token order');
   336 test(function () {
   337 	/* the normative part of the spec states that:
   338 	"unless the length is zero, in which case there are no supported property indices"
   339 	...
   340 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   341 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   342 	assert_equals( makeEl('div',{itemtype:'foo FOO'}).itemType[2], window.undefined );
   343 }, 'itemType[index] must still be undefined for out-of-range index when earlier indexes exist');
   344 test(function () {
   345 	var elem = makeEl('div',{});
   346 	elem.itemType.add('foo');
   347 	elem.itemType.add('FOO');
   348 	assert_equals( elem.getAttribute('itemtype'), 'foo FOO' );
   349 }, 'itemtype attribute must update correctly when items have been added through itemType');
   350 test(function () {
   351 	var elem = makeEl('div',{});
   352 	elem.itemType.add('foo');
   353 	elem.itemType.add('FOO');
   354 	assert_equals( elem.itemType + '', 'foo FOO' );
   355 }, 'itemType must stringify correctly when items have been added');
   356 test(function () {
   357 	var elem = makeEl('div',{itemtype:'foo FOO'});
   358 	elem.itemType.add('foo');
   359 	assert_equals( elem.itemType.length, 2 );
   360 	assert_equals( elem.itemType + '', 'foo FOO' );
   361 }, 'itemType.add must not make any changes if an existing token is added');
   362 test(function () {
   363 	var elem = makeEl('div',{itemtype:'foo FOO'});
   364 	elem.itemType.remove('bar');
   365 	assert_equals( elem.itemType.length, 2 );
   366 	assert_equals( elem.itemType + '', 'foo FOO' );
   367 }, 'itemType.remove must not make any changes if a non-existing token is removed');
   368 test(function () {
   369 	var elem = makeEl('div',{itemtype:'foo FOO'});
   370 	elem.itemType.remove('foo');
   371 	assert_equals( elem.itemType.length, 1 );
   372 	assert_equals( elem.itemType.toString(), 'FOO' );
   373 	assert_false( elem.itemType.contains('foo') );
   374 	assert_true( elem.itemType.contains('FOO') );
   375 }, 'itemType.remove must remove existing tokens');
   376 test(function () {
   377         var elem = makeEl('div',{itemtype:'test test'});
   378         elem.itemType.remove('test');
   379         assert_equals( elem.itemType.length, 0 );
   380         assert_false( elem.itemType.contains('test') );
   381 }, 'itemType.remove must remove duplicated tokens');
   382 test(function () {
   383         var elem = makeEl('div',{itemtype:'token1 token2 token3'});
   384         elem.itemType.remove('token2');
   385         assert_equals( elem.itemType.toString(), 'token1 token3' );
   386 }, 'itemType.remove must collapse whitespace around removed tokens');
   387 test(function () {
   388         var elem = makeEl('div',{itemtype:' token1 token2  '});
   389         elem.itemType.remove('token2');
   390         assert_equals( elem.itemType.toString(), 'token1' );
   391 }, 'itemType.remove must remove all useless whitespace');
   392 test(function () {
   393         var elem = makeEl('div',{itemtype:'  token1  token2  token3  '});
   394         elem.itemType.remove('token2');
   395         assert_equals( elem.itemType.toString(), 'token1 token3' );
   396 }, 'itemType.remove must collapse multiple whitespace around removed tokens');
   397 test(function () {
   398         var elem = makeEl('div',{itemtype:'  token1  token2  token1  '});
   399         elem.itemType.remove('token2');
   400         assert_equals( elem.itemType.toString(), 'token1' );
   401 }, 'itemType.remove must remove duplicates when removing tokens');
   402 test(function () {
   403         var elem = makeEl('div',{itemtype:'  token1  token2  token3  '});
   404         elem.itemType.remove('token1', 'token3');
   405         assert_equals( elem.itemType.toString(), 'token2' );
   406 }, 'itemType.remove must collapse whitespace when removing multiple tokens');
   407 test(function () {
   408         var elem = makeEl('div',{itemtype:'  token1  token2  '});
   409         elem.itemType.add('token1');
   410         assert_equals( elem.itemType.toString(), 'token1 token2' );
   411 }, 'itemType.add must remove unused whitespace when the token already exists');
   412 test(function () {
   413         var elem = makeEl('div',{itemtype:'FOO'});
   414         assert_true(elem.itemType.toggle('foo'));
   415         assert_equals( elem.itemType.length, 2 );
   416         assert_true( elem.itemType.contains('foo') );
   417         assert_true( elem.itemType.contains('FOO') );
   418 }, 'itemType.toggle must toggle tokens case-sensitively when adding');
   419 test(function () {
   420         var elem = makeEl('div',{itemtype:'foo FOO'});
   421         assert_false(elem.itemType.toggle('foo'));
   422         assert_false(elem.itemType.toggle('FOO'));
   423         assert_false( elem.itemType.contains('foo') );
   424         assert_false( elem.itemType.contains('FOO') );
   425 }, 'itemType.toggle must be able to remove tokens case-sensitively');
   426 test(function () {
   427         var elem = makeEl('div',{itemtype:'foo FOO'});
   428         elem.itemType.toggle('foo');
   429         elem.itemType.toggle('FOO');
   430         assert_equals( elem.getAttribute('itemtype'), '' );
   431 }, 'itemtype attribute must be empty when all classes have been removed');
   432 test(function () {
   433         var elem = makeEl('div',{itemtype:'foo FOO'});
   434         elem.itemType.toggle('foo');
   435         elem.itemType.toggle('FOO');
   436         assert_equals( elem.itemType.toString(), '' );
   437 }, 'itemType must stringify to an empty string when all classes have been removed');
   438 test(function () {
   439         var elem = makeEl('div',{itemtype:'foo FOO'});
   440         elem.itemType.toggle('foo');
   441         elem.itemType.toggle('FOO');
   442         assert_equals( elem.itemType.item(0), null );
   443 }, 'itemType.item(0) must return null when all classes have been removed');
   444 test(function () {
   445         /* the normative part of the spec states that:
   446         "unless the length is zero, in which case there are no supported property indices"
   447         ...
   448         "The term[...] supported property indices [is] used as defined in the WebIDL specification."
   449         WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   450         var elem = makeEl('div',{itemtype:'foo FOO'});
   451         elem.itemType.toggle('foo');
   452         elem.itemType.toggle('FOO');
   453         assert_equals( elem.itemType[0], window.undefined );
   454 }, 'itemType[0] must be undefined when all classes have been removed');
   455 //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"
   456 test(function () {
   457         var elem = makeEl('div',{itemtype:'a '});
   458         elem.itemType.add('b');
   459         assert_equals(elem.itemType.toString(),'a b');
   460 }, 'itemType.add should treat " " as a space');
   461 test(function () {
   462         var elem = makeEl('div',{itemtype:'a\t'});
   463         elem.itemType.add('b');
   464         assert_equals(elem.itemType.toString(),'a b');
   465 }, 'itemType.add should normalize \\t as a space');
   466 test(function () {
   467         var elem = makeEl('div',{itemtype:'a\r'});
   468         elem.itemType.add('b');
   469         assert_equals(elem.itemType.toString(),'a b');
   470 }, 'itemType.add should normalize \\r as a space');
   471 test(function () {
   472         var elem = makeEl('div',{itemtype:'a\n'});
   473         elem.itemType.add('b');
   474         assert_equals(elem.itemType.toString(),'a b');
   475 }, 'itemType.add should normalize \\n as a space');
   476 test(function () {
   477         var elem = makeEl('div',{itemtype:'a\f'});
   478         elem.itemType.add('b');
   479         assert_equals(elem.itemType.toString(),'a b');
   480 }, 'itemType.add should normalize \\f as a space');
   481 test(function () {
   482         var elem = makeEl('div',{itemtype:'foo'});
   483         elem.itemType.remove('foo');
   484         elem.removeAttribute('itemtype');
   485         assert_true( elem.itemType.toggle('foo') );
   486 }, 'itemType.toggle must work after removing the itemtype attribute');
   487 test(function () {
   488         //WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
   489         //ES5 makes [[Put]] fail but not throw
   490         var failed = false;
   491         var elem = makeEl('div',{itemtype:'token1'});
   492         try {
   493                 elem.itemType.length = 0;
   494         } catch(e) {
   495                 failed = e;
   496         }
   497         assert_equals(elem.itemType.length,1);
   498         assert_false(failed,'an error was thrown');
   499 }, 'itemType.length must be read-only');
   500 test(function () {
   501         var failed = false, elem = makeEl('div',{itemtype:'test'}), realList = elem.itemType;
   502         try {
   503                 elem.itemType = 'dummy';
   504         } catch(e) {
   505                 failed = e;
   506         }
   507         assert_equals(elem.itemType,realList);
   508         assert_equals(elem.itemType.toString(),'dummy','attempting to write should modify the underlying string');
   509         assert_false(failed,'an error was thrown');
   510 }, 'itemType must be read-only');
   512 /* itemProp property tests (properties collection tests are done later) */
   513 test(function () {
   514 	assert_equals(makeEl('div',{}).itemProp.toString(),'','no attribute');
   515 	assert_equals(makeEl('div',{itemprop:' http://example.com/foo#bar  test '}).itemProp.toString(),' http://example.com/foo#bar  test ','with URL and simple tokens');
   516 	var testEl = makeEl('div',{itemprop:'http://example.com/foo#bar'});
   517 	testEl.removeAttribute('itemprop');
   518 	assert_equals(testEl.itemProp.toString(),'','removed attribute');
   519 }, 'the itemprop attribute must be reflected by the .itemProp property');
   520 test(function () {
   521 	assert_equals( typeof makeEl('div',{}).itemProp, 'object' );
   522 }, 'the itemProp property must be an object');
   523 test(function () {
   524 	assert_true( makeEl('div',{}).itemProp instanceof DOMTokenList, 'instanceof test' );
   525 	DOMTokenList.prototype.customProperty = true;
   526 	assert_true( makeEl('div',{}).itemProp.customProperty, 'inheritance test' );
   527 }, 'the itemProp property must implement DOMTokenList');
   528 test(function () {
   529 	var testEl = makeEl('div',{});
   530 	assert_equals( testEl.itemProp, testEl.itemProp );
   531 }, 'the itemProp property must always reference the same object');
   532 test(function () {
   533 	assert_equals( makeEl('div',{itemprop:'test test'}).itemProp.length, 2, 'duplicates in initial string should be preserved' );
   534 	assert_equals( makeEl('div',{itemprop:'test test'}).itemProp.item(0), 'test' );
   535 	assert_true( makeEl('div',{itemprop:'test test'}).itemProp.contains('test') );
   536 }, 'itemProp must be correct for an element that has itemprop tokens');
   537 test(function () {
   538 	assert_equals( makeEl('div',{itemprop:' '}).itemProp.length, 0 );
   539 }, 'itemProp.length must be 0 for an element that has no tokens');
   540 test(function () {
   541 	assert_false( makeEl('div',{itemprop:' '}).itemProp.contains('foo') );
   542 }, 'itemProp must not contain an undefined class');
   543 test(function () {
   544 	assert_equals( makeEl('div',{itemprop:' '}).itemProp.item(0), null );
   545 }, 'itemProp.item() must return null for out-of-range index');
   546 test(function () {
   547 	assert_equals( makeEl('div',{itemprop:' '}).itemProp.item(-1), null );
   548 }, 'itemProp.item() must return null for negative index');
   549 test(function () {
   550 	/* the normative part of the spec states that:
   551 	"unless the length is zero, in which case there are no supported property indices"
   552 	...
   553 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   554 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   555 	assert_equals( makeEl('div',{itemprop:' '}).itemProp[0], window.undefined );
   556 }, 'itemProp[index] must be undefined for out-of-range index');
   557 test(function () {
   558 	assert_equals( makeEl('div',{itemprop:' '}).itemProp[-1], window.undefined );
   559 }, 'itemProp[index] must be undefined for negative index');
   560 test(function () {
   561 	assert_equals( makeEl('div',{itemprop:' '}).itemProp.toString(), ' ' );
   562 }, 'empty itemProp should stringify to contain the attribute\'s whitespace');
   563 test(function () {
   564 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.contains(''); } );
   565 }, 'itemProp.contains(empty_string) must throw a SYNTAX_ERR');
   566 test(function () {
   567 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.add(''); } );
   568 }, 'itemProp.add(empty_string) must throw a SYNTAX_ERR');
   569 test(function () {
   570 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.remove(''); } );
   571 }, 'itemProp.remove(empty_string) must throw a SYNTAX_ERR');
   572 test(function () {
   573 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.toggle(''); } );
   574 }, 'itemProp.toggle(empty_string) must throw a SYNTAX_ERR');
   575 test(function () {
   576 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.contains('a b'); } );
   577 }, '.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   578 test(function () {
   579 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.add('a b'); } );
   580 }, 'itemProp.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   581 test(function () {
   582 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.remove('a b'); } );
   583 }, 'itemProp.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   584 test(function () {
   585 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemprop:' '}).itemProp.toggle('a b'); } );
   586 }, 'itemProp.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   587 test(function () {
   588 	var testEl = makeEl('div',{itemprop:'foo'});
   589 	assert_true( testEl.itemProp.contains('foo'), 'before change' );
   590 	testEl.setAttribute('itemprop','bar');
   591 	assert_true( testEl.itemProp.contains('bar'), 'after change' );
   592 	assert_false( testEl.itemProp.contains('foo'), 'after change' );
   593 }, 'itemProp.contains must update when the underlying attribute is changed');
   594 test(function () {
   595 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('FOO') );
   596 }, 'itemProp.contains must be case sensitive');
   597 test(function () {
   598 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo.') );
   599 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo)') );
   600 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo\'') );
   601 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo$') );
   602 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo~') );
   603 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo?') );
   604 	assert_false( makeEl('div',{itemprop:'foo'}).itemProp.contains('foo\\') );
   605 }, 'itemProp.contains must not match when punctuation characters are added');
   606 test(function () {
   607 	var elem = makeEl('div',{itemprop:'foo'});
   608 	elem.itemProp.add('FOO');
   609 	assert_true( elem.itemProp.contains('foo') );
   610 }, 'itemProp.add must not remove existing tokens');
   611 test(function () {
   612 	assert_true( makeEl('div',{itemprop:'foo FOO'}).itemProp.contains('FOO') );
   613 }, 'itemProp.contains case sensitivity must match a case-specific string');
   614 test(function () {
   615 	assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp.length, 2 );
   616 }, 'itemProp.length must correctly reflect the number of tokens');
   617 test(function () {
   618 	assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp.item(0), 'foo' );
   619 }, 'itemProp.item(0) must return the first token');
   620 test(function () {
   621 	var elem = makeEl('div',{itemprop:'foo'});
   622 	elem.itemProp.add('FOO');
   623 	assert_equals( elem.itemProp.item(1), 'FOO' );
   624 }, 'itemProp.item must return case-sensitive strings and preserve token order');
   625 test(function () {
   626 	assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[0], 'foo' );
   627 }, 'itemProp[0] must return the first token');
   628 test(function () {
   629 	assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[1], 'FOO' );
   630 }, 'itemProp[index] must return case-sensitive strings and preserve token order');
   631 test(function () {
   632 	/* the normative part of the spec states that:
   633 	"unless the length is zero, in which case there are no supported property indices"
   634 	...
   635 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   636 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   637 	assert_equals( makeEl('div',{itemprop:'foo FOO'}).itemProp[2], window.undefined );
   638 }, 'itemProp[index] must still be undefined for out-of-range index when earlier indexes exist');
   639 test(function () {
   640 	var elem = makeEl('div',{});
   641 	elem.itemProp.add('foo');
   642 	elem.itemProp.add('FOO');
   643 	assert_equals( elem.getAttribute('itemprop'), 'foo FOO' );
   644 }, 'itemprop attribute must update correctly when items have been added through itemProp');
   645 test(function () {
   646 	var elem = makeEl('div',{});
   647 	elem.itemProp.add('foo');
   648 	elem.itemProp.add('FOO');
   649 	assert_equals( elem.itemProp + '', 'foo FOO' );
   650 }, 'itemProp must stringify correctly when items have been added');
   651 test(function () {
   652 	var elem = makeEl('div',{itemprop:'foo FOO'});
   653 	elem.itemProp.add('foo');
   654 	assert_equals( elem.itemProp.length, 2 );
   655 	assert_equals( elem.itemProp + '', 'foo FOO' );
   656 }, 'itemProp.add must not make any changes if an existing token is added');
   657 test(function () {
   658 	var elem = makeEl('div',{itemprop:'foo FOO'});
   659 	elem.itemProp.remove('bar');
   660 	assert_equals( elem.itemProp.length, 2 );
   661 	assert_equals( elem.itemProp + '', 'foo FOO' );
   662 }, 'itemProp.remove must not make any changes if a non-existing token is removed');
   663 test(function () {
   664 	var elem = makeEl('div',{itemprop:'foo FOO'});
   665 	elem.itemProp.remove('foo');
   666 	assert_equals( elem.itemProp.length, 1 );
   667 	assert_equals( elem.itemProp.toString(), 'FOO' );
   668 	assert_false( elem.itemProp.contains('foo') );
   669 	assert_true( elem.itemProp.contains('FOO') );
   670 }, 'itemProp.remove must remove existing tokens');
   671 test(function () {
   672 	var elem = makeEl('div',{itemprop:'test test'});
   673 	elem.itemProp.remove('test');
   674 	assert_equals( elem.itemProp.length, 0 );
   675 	assert_false( elem.itemProp.contains('test') );
   676 }, 'itemProp.remove must remove duplicated tokens');
   677 test(function () {
   678 	var elem = makeEl('div',{itemprop:'token1 token2 token3'});
   679 	elem.itemProp.remove('token2');
   680 	assert_equals( elem.itemProp.toString(), 'token1 token3' );
   681 }, 'itemProp.remove must collapse whitespace around removed tokens');
   682 test(function () {
   683 	var elem = makeEl('div',{itemprop:'  token1  token2  token3  '});
   684 	elem.itemProp.remove('token2');
   685 	assert_equals( elem.itemProp.toString(), 'token1 token3' );
   686 }, 'itemProp.remove must remove all useless whitespace');
   687 test(function () {
   688 	var elem = makeEl('div',{itemprop:'  token1  token2  token3  '});
   689 	elem.itemProp.remove('token1', 'token3');
   690 	assert_equals( elem.itemProp.toString(), 'token2' );
   691 }, 'itemProp.remove must remove useless whitespace when removing multiple tokens');
   692 test(function () {
   693 	var elem = makeEl('div',{itemprop:'  token1  token1  '});
   694 	elem.itemProp.add('token1');
   695 	assert_equals( elem.itemProp.toString(), 'token1' );
   696 }, 'itemProp.add must remove useless whitespace and duplicates when the token already exists');
   697 test(function () {
   698 	var elem = makeEl('div',{itemprop:'FOO'});
   699 	assert_true(elem.itemProp.toggle('foo'));
   700 	assert_equals( elem.itemProp.length, 2 );
   701 	assert_true( elem.itemProp.contains('foo') );
   702 	assert_true( elem.itemProp.contains('FOO') );
   703 }, 'itemProp.toggle must toggle tokens case-sensitively when adding');
   704 test(function () {
   705 	var elem = makeEl('div',{itemprop:'foo FOO'});
   706 	assert_false(elem.itemProp.toggle('foo'));
   707 	assert_false(elem.itemProp.toggle('FOO'));
   708 	assert_false( elem.itemProp.contains('foo') );
   709 	assert_false( elem.itemProp.contains('FOO') );
   710 }, 'itemProp.toggle must be able to remove tokens case-sensitively');
   711 test(function () {
   712 	var elem = makeEl('div',{itemprop:'foo FOO'});
   713 	elem.itemProp.toggle('foo');
   714 	elem.itemProp.toggle('FOO');
   715 	assert_equals( elem.getAttribute('itemprop'), '' );
   716 }, 'itemprop attribute must be empty when all classes have been removed');
   717 test(function () {
   718 	var elem = makeEl('div',{itemprop:'foo FOO'});
   719 	elem.itemProp.toggle('foo');
   720 	elem.itemProp.toggle('FOO');
   721 	assert_equals( elem.itemProp.toString(), '' );
   722 }, 'itemProp must stringify to an empty string when all classes have been removed');
   723 test(function () {
   724 	var elem = makeEl('div',{itemprop:'foo FOO'});
   725 	elem.itemProp.toggle('foo');
   726 	elem.itemProp.toggle('FOO');
   727 	assert_equals( elem.itemProp.item(0), null );
   728 }, 'itemProp.item(0) must return null when all classes have been removed');
   729 test(function () {
   730 	/* the normative part of the spec states that:
   731 	"unless the length is zero, in which case there are no supported property indices"
   732 	...
   733 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   734 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   735 	var elem = makeEl('div',{itemprop:'foo FOO'});
   736 	elem.itemProp.toggle('foo');
   737 	elem.itemProp.toggle('FOO');
   738 	assert_equals( elem.itemProp[0], window.undefined );
   739 }, 'itemProp[0] must be undefined when all classes have been removed');
   740 //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"
   741 test(function () {
   742 	var elem = makeEl('div',{itemprop:'a '});
   743 	elem.itemProp.add('b');
   744 	assert_equals(elem.itemProp.toString(),'a b');
   745 }, 'itemProp.add should treat " " as a space');
   746 test(function () {
   747 	var elem = makeEl('div',{itemprop:'a\t'});
   748 	elem.itemProp.add('b');
   749 	assert_equals(elem.itemProp.toString(),'a b');
   750 }, 'itemProp.add should normalize \\t as a space');
   751 test(function () {
   752 	var elem = makeEl('div',{itemprop:'a\r'});
   753 	elem.itemProp.add('b');
   754 	assert_equals(elem.itemProp.toString(),'a b');
   755 }, 'itemProp.add should normalize \\r as a space');
   756 test(function () {
   757 	var elem = makeEl('div',{itemprop:'a\n'});
   758 	elem.itemProp.add('b');
   759 	assert_equals(elem.itemProp.toString(),'a b');
   760 }, 'itemProp.add should normalize \\n as a space');
   761 test(function () {
   762 	var elem = makeEl('div',{itemprop:'a\f'});
   763 	elem.itemProp.add('b');
   764 	assert_equals(elem.itemProp.toString(),'a b');
   765 }, 'itemProp.add should normalize \\f as a space');
   766 test(function () {
   767 	var elem = makeEl('div',{itemprop:'foo'});
   768 	elem.itemProp.remove('foo');
   769 	elem.removeAttribute('itemprop');
   770 	assert_true( elem.itemProp.toggle('foo') );
   771 }, 'itemProp.toggle must work after removing the itemprop attribute');
   772 test(function () {
   773 	//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
   774 	//ES5 makes [[Put]] fail but not throw
   775 	var failed = false;
   776 	var elem = makeEl('div',{itemprop:'token1'});
   777 	try {
   778 		elem.itemProp.length = 0;
   779 	} catch(e) {
   780 		failed = e;
   781 	}
   782 	assert_equals(elem.itemProp.length,1);
   783 	assert_false(failed,'an error was thrown');
   784 }, 'itemProp.length must be read-only');
   785 test(function () {
   786 	var failed = false, elem = makeEl('div',{itemprop:'test'}), realList = elem.itemProp;
   787 	try {
   788 		elem.itemProp = 'dummy';
   789 	} catch(e) {
   790 		failed = e;
   791 	}
   792 	assert_equals(elem.itemProp,realList);
   793 	assert_equals(elem.itemProp.toString(),'dummy','attempting to write should modify the underlying string');
   794 	assert_false(failed,'an error was thrown');
   795 }, 'itemProp must be read-only');
   797 /* itemId property tests */
   798 test(function () {
   799 	assert_equals( makeEl('div',{itemid:'http://example.com/foo'}).itemId, 'http://example.com/foo' );
   800 	assert_equals( makeEl('div',{itemid:'http://example.com/FOO'}).itemId, 'http://example.com/FOO', 'case-sensitive' );
   801 	assert_equals( makeEl('div',{itemid:' http://example.com/foo '}).itemId, 'http://example.com/foo', 'whitespace' );
   802 	assert_equals( makeEl('div',{itemid:'data:text/plain,'}).itemId, 'data:text/plain,' );
   803 	assert_equals( makeEl('div',{itemid:'madeup:onthespot'}).itemId, 'madeup:onthespot' );
   804 	assert_equals( makeEl('div',{}).itemId, '' );
   805 }, 'the itemid attribute must be reflected by the .itemId property');
   806 test(function () {
   807 	var testEl = makeEl('div',{});
   808 	testEl.itemId = 'http://example.com/foo';
   809 	assert_equals(testEl.itemId,'http://example.com/foo','writing a URL');
   810 	testEl.itemId = '';
   811 	assert_equals(testEl.itemId,location.href,'writing an empty string');
   812 }, 'the itemId property must be read/write');
   813 test(function () {
   814 	var testEl = makeEl('div',{});
   815 	testEl.itemId = 'http://example.com/foo';
   816 	assert_true(testEl.hasAttribute('itemid'),'writing a URL');
   817 	assert_equals(testEl.getAttribute('itemid'),'http://example.com/foo','writing a URL');
   818 	testEl = makeEl('div',{})
   819 	testEl.itemId = '';
   820 	assert_true(testEl.hasAttribute('itemid'),'writing an empty string');
   821 	assert_equals(testEl.getAttribute('itemid'),'','writing an empty string');
   822 }, 'writing to the itemId property must create the itemid content attribute');
   823 test(function () {
   824 	assert_equals( makeEl('div',{itemid:'foo'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo'),'foo' );
   825 	assert_equals( makeEl('div',{itemid:'foo bar'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo%20bar'),'foo bar' );
   826 	assert_equals( makeEl('div',{itemid:'foo\u0129 bar'}).itemId, location.href.replace(/\/[^\/]*$/,'\/foo%C4%A9%20bar'),'foo\u0129 bar' );
   827 }, 'the itemId property must see the resolved itemid URL');
   828 test(function () {
   829 	var testEl = makeEl('div',{});
   830 	testEl.itemId = 'foo';
   831 	assert_equals( testEl.itemId, location.href.replace(/\/[^\/]*$/,'\/foo') );
   832 }, 'the itemId property must see the resolved itemId property URL on setting');
   833 test(function () {
   834 	var testEl = makeEl('div',{});
   835 	testEl.itemId = 'foo';
   836 	assert_equals( testEl.getAttribute('itemid'), 'foo' );
   837 }, 'the itemid attribute must see the resolved itemId URL');
   839 /* itemRef property tests (properties collection tests are done later) */
   840 test(function () {
   841 	assert_equals(makeEl('div',{}).itemRef.toString(),'','no attribute');
   842 	assert_equals(makeEl('div',{itemref:' foo  bar '}).itemRef.toString(),' foo  bar ','with simple tokens');
   843 	var testEl = makeEl('div',{itemref:'foo'});
   844 	testEl.removeAttribute('itemref');
   845 	assert_equals(testEl.itemRef.toString(),'','removed attribute');
   846 }, 'the itemref attribute must be reflected by the .itemRef property');
   847 test(function () {
   848 	assert_equals( typeof makeEl('div',{}).itemRef, 'object' );
   849 }, 'the itemRef property must be an object');
   850 test(function () {
   851 	assert_true( makeEl('div',{}).itemRef instanceof DOMTokenList, 'instanceof test' );
   852 	DOMTokenList.prototype.customProperty = true;
   853 	assert_true( makeEl('div',{}).itemRef.customProperty, 'inheritance test' );
   854 }, 'the itemRef property must implement DOMTokenList');
   855 test(function () {
   856 	var testEl = makeEl('div',{});
   857 	assert_equals( testEl.itemRef, testEl.itemRef );
   858 }, 'the itemRef property must always reference the same object');
   859 test(function () {
   860 	assert_equals( makeEl('div',{itemref:'test test'}).itemRef.length, 2, 'duplicates in initial string should be preserved' );
   861 	assert_equals( makeEl('div',{itemref:'test test'}).itemRef.item(0), 'test' );
   862 	assert_true( makeEl('div',{itemref:'test test'}).itemRef.contains('test') );
   863 }, 'itemRef must be correct for an element that has itemref tokens');
   864 test(function () {
   865 	assert_equals( makeEl('div',{itemref:' '}).itemRef.length, 0 );
   866 }, 'itemRef.length must be 0 for an element that has no tokens');
   867 test(function () {
   868 	assert_false( makeEl('div',{itemref:' '}).itemRef.contains('foo') );
   869 }, 'itemRef must not contain an undefined class');
   870 test(function () {
   871 	assert_equals( makeEl('div',{itemref:' '}).itemRef.item(0), null );
   872 }, 'itemRef.item() must return null for out-of-range index');
   873 test(function () {
   874 	assert_equals( makeEl('div',{itemref:' '}).itemRef.item(-1), null );
   875 }, 'itemRef.item() must return null for negative index');
   876 test(function () {
   877 	/* the normative part of the spec states that:
   878 	"unless the length is zero, in which case there are no supported property indices"
   879 	...
   880 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   881 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   882 	assert_equals( makeEl('div',{itemref:' '}).itemRef[0], window.undefined );
   883 }, 'itemRef[index] must be undefined for out-of-range index');
   884 test(function () {
   885 	assert_equals( makeEl('div',{itemref:' '}).itemRef[-1], window.undefined );
   886 }, 'itemRef[index] must be undefined for negative index');
   887 test(function () {
   888 	assert_equals( makeEl('div',{itemref:' '}).itemRef.toString(), ' ' );
   889 }, 'empty itemRef should stringify to contain the attribute\'s whitespace');
   890 test(function () {
   891 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.contains(''); } );
   892 }, 'itemRef.contains(empty_string) must throw a SYNTAX_ERR');
   893 test(function () {
   894 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.add(''); } );
   895 }, 'itemRef.add(empty_string) must throw a SYNTAX_ERR');
   896 test(function () {
   897 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.remove(''); } );
   898 }, 'itemRef.remove(empty_string) must throw a SYNTAX_ERR');
   899 test(function () {
   900 	assert_throws( 'SYNTAX_ERR', function () { makeEl('div',{itemref:' '}).itemRef.toggle(''); } );
   901 }, 'itemRef.toggle(empty_string) must throw a SYNTAX_ERR');
   902 test(function () {
   903 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.contains('a b'); } );
   904 }, 'itemRef.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   905 test(function () {
   906 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.add('a b'); } );
   907 }, 'itemRef.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   908 test(function () {
   909 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.remove('a b'); } );
   910 }, 'itemRef.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   911 test(function () {
   912 	assert_throws( 'INVALID_CHARACTER_ERR', function () { makeEl('div',{itemref:' '}).itemRef.toggle('a b'); } );
   913 }, 'itemRef.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
   914 test(function () {
   915 	var testEl = makeEl('div',{itemref:'foo'});
   916 	assert_true( testEl.itemRef.contains('foo'), 'before change' );
   917 	testEl.setAttribute('itemref','bar');
   918 	assert_true( testEl.itemRef.contains('bar'), 'after change' );
   919 	assert_false( testEl.itemRef.contains('foo'), 'after change' );
   920 }, 'itemRef.contains must update when the underlying attribute is changed');
   921 test(function () {
   922 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('FOO') );
   923 }, 'itemRef.contains must be case sensitive');
   924 test(function () {
   925 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo.') );
   926 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo)') );
   927 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo\'') );
   928 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo$') );
   929 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo~') );
   930 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo?') );
   931 	assert_false( makeEl('div',{itemref:'foo'}).itemRef.contains('foo\\') );
   932 }, 'itemRef.contains must not match when punctuation characters are added');
   933 test(function () {
   934 	var elem = makeEl('div',{itemref:'foo'});
   935 	elem.itemRef.add('FOO');
   936 	assert_true( elem.itemRef.contains('foo') );
   937 }, 'itemRef.add must not remove existing tokens');
   938 test(function () {
   939 	assert_true( makeEl('div',{itemref:'foo FOO'}).itemRef.contains('FOO') );
   940 }, 'itemRef.contains case sensitivity must match a case-specific string');
   941 test(function () {
   942 	assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef.length, 2 );
   943 }, 'itemRef.length must correctly reflect the number of tokens');
   944 test(function () {
   945 	assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef.item(0), 'foo' );
   946 }, 'itemRef.item(0) must return the first token');
   947 test(function () {
   948 	var elem = makeEl('div',{itemref:'foo'});
   949 	elem.itemRef.add('FOO');
   950 	assert_equals( elem.itemRef.item(1), 'FOO' );
   951 }, 'itemRef.item must return case-sensitive strings and preserve token order');
   952 test(function () {
   953 	assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[0], 'foo' );
   954 }, 'itemRef[0] must return the first token');
   955 test(function () {
   956 	assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[1], 'FOO' );
   957 }, 'itemRef[index] must return case-sensitive strings and preserve token order');
   958 test(function () {
   959 	/* the normative part of the spec states that:
   960 	"unless the length is zero, in which case there are no supported property indices"
   961 	...
   962 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
   963 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
   964 	assert_equals( makeEl('div',{itemref:'foo FOO'}).itemRef[2], window.undefined );
   965 }, 'itemRef[index] must still be undefined for out-of-range index when earlier indexes exist');
   966 test(function () {
   967 	var elem = makeEl('div',{});
   968 	elem.itemRef.add('foo');
   969 	elem.itemRef.add('FOO');
   970 	assert_equals( elem.getAttribute('itemref'), 'foo FOO' );
   971 }, 'itemref attribute must update correctly when items have been added through itemRef');
   972 test(function () {
   973 	var elem = makeEl('div',{});
   974 	elem.itemRef.add('foo');
   975 	elem.itemRef.add('FOO');
   976 	assert_equals( elem.itemRef + '', 'foo FOO' );
   977 }, 'itemRef must stringify correctly when items have been added');
   978 test(function () {
   979 	var elem = makeEl('div',{itemref:'foo FOO'});
   980 	elem.itemRef.add('foo');
   981 	assert_equals( elem.itemRef.length, 2 );
   982 	assert_equals( elem.itemRef + '', 'foo FOO' );
   983 }, 'itemRef.add must not make any changes if an existing token is added');
   984 test(function () {
   985 	var elem = makeEl('div',{itemref:'foo FOO'});
   986 	elem.itemRef.remove('bar');
   987 	assert_equals( elem.itemRef.length, 2 );
   988 	assert_equals( elem.itemRef + '', 'foo FOO' );
   989 }, 'itemRef.remove must not make any changes if a non-existing token is removed');
   990 test(function () {
   991 	var elem = makeEl('div',{itemref:'foo FOO'});
   992 	elem.itemRef.remove('foo');
   993 	assert_equals( elem.itemRef.length, 1 );
   994 	assert_equals( elem.itemRef.toString(), 'FOO' );
   995 	assert_false( elem.itemRef.contains('foo') );
   996 	assert_true( elem.itemRef.contains('FOO') );
   997 }, 'itemRef.remove must remove existing tokens');
   998 test(function () {
   999 	var elem = makeEl('div',{itemref:'test test'});
  1000 	elem.itemRef.remove('test');
  1001 	assert_equals( elem.itemRef.length, 0 );
  1002 	assert_false( elem.itemRef.contains('test') );
  1003 }, 'itemRef.remove must remove duplicated tokens');
  1004 test(function () {
  1005 	var elem = makeEl('div',{itemref:'token1 token2 token3'});
  1006 	elem.itemRef.remove('token2');
  1007 	assert_equals( elem.itemRef.toString(), 'token1 token3' );
  1008 }, 'itemRef.remove must collapse whitespace around removed tokens');
  1009 test(function () {
  1010 	var elem = makeEl('div',{itemref:' token1 token2  '});
  1011 	elem.itemRef.remove('token2');
  1012 	assert_equals( elem.itemRef.toString(), 'token1' );
  1013 }, 'itemRef.remove must remove useless whitespace when removing tokens');
  1014 test(function () {
  1015 	var elem = makeEl('div',{itemref:'  token1  token2  token3  '});
  1016 	elem.itemRef.remove('token2');
  1017 	assert_equals( elem.itemRef.toString(), 'token1 token3' );
  1018 }, 'itemRef.remove must remove useless whitespace when removing tokens');
  1019 test(function () {
  1020 	var elem = makeEl('div',{itemref:'  token1  token2  token3  '});
  1021 	elem.itemRef.remove('token1', 'token3');
  1022 	assert_equals( elem.itemRef.toString(), 'token2' );
  1023 }, 'itemRef.remove must collapse whitespace when removing multiple tokens');
  1024 test(function () {
  1025 	var elem = makeEl('div',{itemref:'  token1  token1  '});
  1026 	elem.itemRef.add('token1');
  1027 	assert_equals( elem.itemRef.toString(), 'token1' );
  1028 }, 'itemRef.add must remove whitespace and duplicate when the token already exists');
  1029 test(function () {
  1030 	var elem = makeEl('div',{itemref:'FOO'});
  1031 	assert_true(elem.itemRef.toggle('foo'));
  1032 	assert_equals( elem.itemRef.length, 2 );
  1033 	assert_true( elem.itemRef.contains('foo') );
  1034 	assert_true( elem.itemRef.contains('FOO') );
  1035 }, 'itemRef.toggle must toggle tokens case-sensitively when adding');
  1036 test(function () {
  1037 	var elem = makeEl('div',{itemref:'foo FOO'});
  1038 	assert_false(elem.itemRef.toggle('foo'));
  1039 	assert_false(elem.itemRef.toggle('FOO'));
  1040 	assert_false( elem.itemRef.contains('foo') );
  1041 	assert_false( elem.itemRef.contains('FOO') );
  1042 }, 'itemRef.toggle must be able to remove tokens case-sensitively');
  1043 test(function () {
  1044 	var elem = makeEl('div',{itemref:'foo FOO'});
  1045 	elem.itemRef.toggle('foo');
  1046 	elem.itemRef.toggle('FOO');
  1047 	assert_equals( elem.getAttribute('itemref'), '' );
  1048 }, 'itemref attribute must be empty when all classes have been removed');
  1049 test(function () {
  1050 	var elem = makeEl('div',{itemref:'foo FOO'});
  1051 	elem.itemRef.toggle('foo');
  1052 	elem.itemRef.toggle('FOO');
  1053 	assert_equals( elem.itemRef.toString(), '' );
  1054 }, 'itemRef must stringify to an empty string when all classes have been removed');
  1055 test(function () {
  1056 	var elem = makeEl('div',{itemref:'foo FOO'});
  1057 	elem.itemRef.toggle('foo');
  1058 	elem.itemRef.toggle('FOO');
  1059 	assert_equals( elem.itemRef.item(0), null );
  1060 }, 'itemRef.item(0) must return null when all classes have been removed');
  1061 test(function () {
  1062 	/* the normative part of the spec states that:
  1063 	"unless the length is zero, in which case there are no supported property indices"
  1064 	...
  1065 	"The term[...] supported property indices [is] used as defined in the WebIDL specification."
  1066 	WebIDL creates actual OwnProperties and then [] just acts as a normal property lookup */
  1067 	var elem = makeEl('div',{itemref:'foo FOO'});
  1068 	elem.itemRef.toggle('foo');
  1069 	elem.itemRef.toggle('FOO');
  1070 	assert_equals( elem.itemRef[0], window.undefined );
  1071 }, 'itemRef[0] must be undefined when all classes have been removed');
  1072 //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"
  1073 test(function () {
  1074 	var elem = makeEl('div',{itemref:'a '});
  1075 	elem.itemRef.add('b');
  1076 	assert_equals(elem.itemRef.toString(),'a b');
  1077 }, 'itemRef.add should treat " " as a space');
  1078 test(function () {
  1079 	var elem = makeEl('div',{itemref:'a\t'});
  1080 	elem.itemRef.add('b');
  1081 	assert_equals(elem.itemRef.toString(),'a b');
  1082 }, 'itemRef.add should normalize \\t as a space');
  1083 test(function () {
  1084 	var elem = makeEl('div',{itemref:'a\r'});
  1085 	elem.itemRef.add('b');
  1086 	assert_equals(elem.itemRef.toString(),'a b');
  1087 }, 'itemRef.add should normalize \\r as a space');
  1088 test(function () {
  1089 	var elem = makeEl('div',{itemref:'a\n'});
  1090 	elem.itemRef.add('b');
  1091 	assert_equals(elem.itemRef.toString(),'a b');
  1092 }, 'itemRef.add should normalize \\n as a space');
  1093 test(function () {
  1094 	var elem = makeEl('div',{itemref:'a\f'});
  1095 	elem.itemRef.add('b');
  1096 	assert_equals(elem.itemRef.toString(),'a b');
  1097 }, 'itemRef.add should normalize \\f as a space');
  1098 test(function () {
  1099 	var elem = makeEl('div',{itemref:'foo'});
  1100 	elem.itemRef.remove('foo');
  1101 	elem.removeAttribute('itemref');
  1102 	assert_true( elem.itemRef.toggle('foo') );
  1103 }, 'itemRef.toggle must work after removing the itemref attribute');
  1104 test(function () {
  1105 	//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
  1106 	//ES5 makes [[Put]] fail but not throw
  1107 	var failed = false;
  1108 	var elem = makeEl('div',{itemref:'token1'});
  1109 	try {
  1110 		elem.itemRef.length = 0;
  1111 	} catch(e) {
  1112 		failed = e;
  1114 	assert_equals(elem.itemRef.length,1);
  1115 	assert_false(failed,'an error was thrown');
  1116 }, 'itemRef.length must be read-only');
  1117 test(function () {
  1118 	var failed = false, elem = makeEl('div',{itemref:'test'}), realList = elem.itemRef;
  1119 	try {
  1120 		elem.itemRef = 'dummy';
  1121 	} catch(e) {
  1122 		failed = e;
  1124 	assert_equals(elem.itemRef,realList);
  1125 	assert_equals(elem.itemRef.toString(),'dummy','attempting to write should modify the underlying string');
  1126 	assert_false(failed,'an error was thrown');
  1127 }, 'itemRef must be read-only');
  1129 /* itemValue property tests */
  1130 test(function () {
  1131 	assert_equals( makeEl('meta',{content:'test'}).itemValue, null, 'meta' );
  1132 	assert_equals( makeEl('audio',{src:'test'}).itemValue, null, 'audio' );
  1133 	assert_equals( makeEl('embed',{src:'test'}).itemValue, null, 'embed' );
  1134 	assert_equals( makeEl('iframe',{src:'test'}).itemValue, null, 'iframe' );
  1135 	assert_equals( makeEl('img',{src:'test'}).itemValue, null, 'img' );
  1136 	assert_equals( makeEl('source',{src:'test'}).itemValue, null, 'source' );
  1137 	assert_equals( makeEl('track',{src:'test'}).itemValue, null, 'track' );
  1138 	assert_equals( makeEl('video',{src:'test'}).itemValue, null, 'video' );
  1139 	assert_equals( makeEl('a',{href:'test'}).itemValue, null, 'a' );
  1140 	assert_equals( makeEl('area',{href:'test'}).itemValue, null, 'area' );
  1141 	assert_equals( makeEl('link',{href:'test'}).itemValue, null, 'link' );
  1142 	assert_equals( makeEl('object',{data:'test'}).itemValue, null, 'object' );
  1143 	assert_equals( makeEl('time',{}).itemValue, null, 'time without datetime' );
  1144 	assert_equals( makeEl('time',{datetime:'test'}).itemValue, null, 'time with datetime' );
  1145 	assert_equals( makeEl('div',{},'test').itemValue, null, 'otherwise' );
  1146 	assert_equals( makeEl('madeuponthespot',{},'test').itemValue, null, 'unknown element' );
  1147 }, 'itemValue must be null if the element does not have an itemprop attribute');
  1148 test(function () {
  1149 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('meta',{content:'test'}); testEl.itemValue = 'test2'; }, 'meta' );
  1150 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('audio',{content:'test'}); testEl.itemValue = 'test2'; }, 'audio' );
  1151 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('embed',{content:'test'}); testEl.itemValue = 'test2'; }, 'embed' );
  1152 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('iframe',{content:'test'}); testEl.itemValue = 'test2'; }, 'iframe' );
  1153 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('img',{content:'test'}); testEl.itemValue = 'test2'; }, 'img' );
  1154 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('source',{content:'test'}); testEl.itemValue = 'test2'; }, 'source' );
  1155 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('track',{content:'test'}); testEl.itemValue = 'test2'; }, 'track' );
  1156 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('video',{content:'test'}); testEl.itemValue = 'test2'; }, 'video' );
  1157 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('a',{href:'test'}); testEl.itemValue = 'test2'; }, 'a' );
  1158 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('area',{href:'test'}); testEl.itemValue = 'test2'; }, 'area' );
  1159 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('link',{href:'test'}); testEl.itemValue = 'test2'; }, 'link' );
  1160 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('object',{data:'test'}); testEl.itemValue = 'test2'; }, 'object' );
  1161 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('time',{}); testEl.itemValue = 'test2'; }, 'time without datetime' );
  1162 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('time',{datetime:'test'}); testEl.itemValue = 'test2'; }, 'time with datetime' );
  1163 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('div',{},'test'); testEl.itemValue = 'test2'; }, 'otherwise' );
  1164 	assert_throws( 'INVALID_ACCESS_ERR', function () { var testEl = makeEl('madeuponthespot',{},'test'); testEl.itemValue = 'test2'; }, 'unknown element' );
  1165 }, 'writing to itemValue must throw an INVALID_ACCESS_ERR error if the element does not have an itemprop attribute');
  1166 test(function () {
  1167 	var testEl;
  1168 	testEl = makeEl('meta',{itemscope:'itemscope',itemprop:'foo',content:'test'});
  1169 	assert_equals( testEl.itemValue, testEl, 'meta' );
  1170 	testEl = makeEl('audio',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
  1171 	assert_equals( testEl.itemValue, testEl, 'audio' );
  1172 	testEl = makeEl('embed',{itemscope:'itemscope',itemprop:'foo',src:'test'});
  1173 	assert_equals( testEl.itemValue, testEl, 'embed' );
  1174 	testEl = makeEl('iframe',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
  1175 	assert_equals( testEl.itemValue, testEl, 'iframe' );
  1176 	testEl = makeEl('img',{itemscope:'itemscope',itemprop:'foo',src:'test'});
  1177 	assert_equals( testEl.itemValue, testEl, 'img' );
  1178 	testEl = makeEl('source',{itemscope:'itemscope',itemprop:'foo',src:'test'});
  1179 	assert_equals( testEl.itemValue, testEl, 'source' );
  1180 	testEl = makeEl('track',{itemscope:'itemscope',itemprop:'foo',src:'test'});
  1181 	assert_equals( testEl.itemValue, testEl, 'track' );
  1182 	testEl = makeEl('video',{itemscope:'itemscope',itemprop:'foo',src:'test'},'fail');
  1183 	assert_equals( testEl.itemValue, testEl, 'video' );
  1184 	testEl = makeEl('a',{itemscope:'itemscope',itemprop:'foo',href:'test'},'fail');
  1185 	assert_equals( testEl.itemValue, testEl, 'a' );
  1186 	testEl = makeEl('area',{itemscope:'itemscope',itemprop:'foo',href:'test'});
  1187 	assert_equals( testEl.itemValue, testEl, 'area' );
  1188 	testEl = makeEl('link',{itemscope:'itemscope',itemprop:'foo',href:'test'});
  1189 	assert_equals( testEl.itemValue, testEl, 'link' );
  1190 	testEl = makeEl('object',{itemscope:'itemscope',itemprop:'foo',data:'test'},'fail');
  1191 	assert_equals( testEl.itemValue, testEl, 'object' );
  1192 	testEl = makeEl('time',{itemscope:'itemscope',itemprop:'foo'},'fail');
  1193 	assert_equals( testEl.itemValue, testEl, 'time without datetime' );
  1194 	testEl = makeEl('time',{itemscope:'itemscope',itemprop:'foo',datetime:'test'},'fail');
  1195 	assert_equals( testEl.itemValue, testEl, 'time with datetime' );
  1196 	testEl = makeEl('div',{itemscope:'itemscope',itemprop:'foo'},'test');
  1197 	assert_equals( testEl.itemValue, testEl, 'otherwise' );
  1198 	testEl = makeEl('madeuponthespot',{itemscope:'itemscope',itemprop:'foo'},'test');
  1199 	assert_equals( testEl.itemValue, testEl, 'unknown element' );
  1200 	testEl = makeEl('madeuponthespot',{itemscope:'itemscope',itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test');
  1201 	assert_equals( testEl.itemValue, testEl, 'unknown element with known attributes' );
  1202 	testEl = makeEl('input',{itemscope:'itemscope',itemprop:'foo',value:'test'},'test');
  1203 	assert_equals( testEl.itemValue, testEl, 'input' );
  1204 }, 'itemValue must return the element if the element has an itemscope attribute');
  1205 test(function () {
  1206 	var testEl = makeEl('meta',{itemprop:'foo',content:'test'});
  1207 	assert_equals( testEl.itemValue, 'test', 'reading' );
  1208 	testEl.content = 'retest';
  1209 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1210 	testEl.itemValue = 'bar';
  1211 	assert_equals( testEl.content, 'bar', 'writing (checking content)' );
  1212 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1213 }, 'itemValue must reflect the content attribute on meta elements');
  1214 test(function () {
  1215 	var testEl = makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text');
  1216 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1217 	testEl.src = 'http://example.net/';
  1218 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1219 	testEl.itemValue = 'http://example.com/';
  1220 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1221 	assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
  1222 	assert_equals( makeEl('audio',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
  1223 	testEl.src = 'bar';
  1224 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1225 }, 'itemValue must reflect the src attribute on audio elements');
  1226 test(function () {
  1227 	var testEl = makeEl('embed',{itemprop:'foo',src:'http://example.org/'});
  1228 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1229 	testEl.src = 'http://example.net/';
  1230 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1231 	testEl.itemValue = 'http://example.com/';
  1232 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1233 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1234 	testEl.src = 'bar';
  1235 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1236 }, 'itemValue must reflect the src attribute on embed elements');
  1237 test(function () {
  1238 	var testEl = makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text');
  1239 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1240 	testEl.src = 'http://example.net/';
  1241 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1242 	testEl.itemValue = 'http://example.com/';
  1243 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1244 	assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
  1245 	assert_equals( makeEl('iframe',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
  1246 	testEl.src = 'bar';
  1247 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1248 }, 'itemValue must reflect the src attribute on iframe elements');
  1249 test(function () {
  1250 	var testEl = makeEl('img',{itemprop:'foo',src:'http://example.org/'});
  1251 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1252 	testEl.src = 'http://example.net/';
  1253 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1254 	testEl.itemValue = 'http://example.com/';
  1255 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1256 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1257 	testEl.src = 'bar';
  1258 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1259 }, 'itemValue must reflect the src attribute on img elements');
  1260 test(function () {
  1261 	var testEl = makeEl('source',{itemprop:'foo',src:'http://example.org/'});
  1262 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1263 	testEl.src = 'http://example.net/';
  1264 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1265 	testEl.itemValue = 'http://example.com/';
  1266 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1267 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1268 	testEl.src = 'bar';
  1269 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1270 }, 'itemValue must reflect the src attribute on source elements');
  1271 test(function () {
  1272 	var testEl = makeEl('track',{itemprop:'foo',src:'http://example.org/'});
  1273 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1274 	testEl.src = 'http://example.net/';
  1275 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1276 	testEl.itemValue = 'http://example.com/';
  1277 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1278 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1279 	testEl.src = 'bar';
  1280 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1281 }, 'itemValue must reflect the src attribute on track elements');
  1282 test(function () {
  1283 	var testEl = makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text');
  1284 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1285 	testEl.src = 'http://example.net/';
  1286 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1287 	testEl.itemValue = 'http://example.com/';
  1288 	assert_equals( testEl.src, 'http://example.com/', 'writing (checking src)' );
  1289 	assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
  1290 	assert_equals( makeEl('video',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
  1291 	testEl.src = 'bar';
  1292 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1293 }, 'itemValue must reflect the src attribute on video elements');
  1294 test(function () {
  1295 	var testEl = makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text');
  1296 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1297 	testEl.href = 'http://example.net/';
  1298 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1299 	testEl.itemValue = 'http://example.com/';
  1300 	assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
  1301 	assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
  1302 	assert_equals( makeEl('a',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
  1303 	testEl.href = 'bar';
  1304 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1305 }, 'itemValue must reflect the src attribute on anchor elements');
  1306 test(function () {
  1307 	var testEl = makeEl('area',{itemprop:'foo',href:'http://example.org/'});
  1308 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1309 	testEl.href = 'http://example.net/';
  1310 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1311 	testEl.itemValue = 'http://example.com/';
  1312 	assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
  1313 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1314 	testEl.href = 'bar';
  1315 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1316 }, 'itemValue must reflect the src attribute on area elements');
  1317 test(function () {
  1318 	var testEl = makeEl('link',{itemprop:'foo',href:'http://example.org/'});
  1319 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1320 	testEl.href = 'http://example.net/';
  1321 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1322 	testEl.itemValue = 'http://example.com/';
  1323 	assert_equals( testEl.href, 'http://example.com/', 'writing (checking href)' );
  1324 	assert_equals( testEl.textContent, '', 'writing (checking textContent)' );
  1325 	testEl.href = 'bar';
  1326 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1327 }, 'itemValue must reflect the src attribute on link elements');
  1328 test(function () {
  1329 	var testEl = makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text');
  1330 	assert_equals( testEl.itemValue, 'http://example.org/', 'reading' );
  1331 	testEl.data = 'http://example.net/';
  1332 	assert_equals( testEl.itemValue, 'http://example.net/', 'reading after change' );
  1333 	testEl.itemValue = 'http://example.com/';
  1334 	assert_equals( testEl.data, 'http://example.com/', 'writing (checking data)' );
  1335 	assert_equals( testEl.textContent, 'contained text', 'writing (checking textContent)' );
  1336 	assert_equals( makeEl('object',{itemprop:'foo'},'contained text').itemValue, '', 'reading with missing attribute' );
  1337 	testEl.data = 'bar';
  1338 	assert_equals( testEl.itemValue, location.href.replace(/\/[^\/]*$/,'/bar'), 'resolving URLs' );
  1339 }, 'itemValue must reflect the src attribute on object elements');
  1340 test(function () {
  1341 	var testEl = makeEl('time',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
  1342 	assert_equals( testEl.itemValue, 'te st ing', 'reading' );
  1343 	testEl.innerHTML = 'retest';
  1344 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1345 	testEl.itemValue = '2001-02-03T04:05:06Z';
  1346 	assert_equals( testEl.dateTime, '2001-02-03T04:05:06Z', 'writing (checking dateTime)' );
  1347 	assert_equals( testEl.textContent, 'retest', 'writing (checking textContent)' );
  1348 	assert_equals( testEl.itemValue, '2001-02-03T04:05:06Z', 'writing (checking itemValue)' );
  1349 }, 'itemValue must reflect the dateTime attribute of time elements with no datetime attribute');
  1350 test(function () {
  1351 	var testEl = makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="bar" itemscope>st</span> ing');
  1352 	assert_equals( testEl.itemValue, 'test', 'reading' );
  1353 	testEl.dateTime = 'retest';
  1354 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1355 	testEl.itemValue = '2001-02-03T04:05:06Z';
  1356 	assert_equals( testEl.dateTime, '2001-02-03T04:05:06Z', 'writing (checking dateTime)' );
  1357 	assert_equals( testEl.textContent, 'te st ing', 'writing (checking textContent)' );
  1358 }, 'itemValue must reflect the datetime attribute of time elements with a datetime attribute');
  1359 test(function () {
  1360 	var testEl = makeEl('div',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
  1361 	assert_equals( testEl.itemValue, 'te st ing', 'reading' );
  1362 	testEl.innerHTML = 're<strong>te</strong>st';
  1363 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1364 	testEl.itemValue = 'test';
  1365 	assert_equals( testEl.textContent, 'test', 'writing' );
  1366 }, 'itemValue must reflect the textContent of other elements');
  1367 test(function () {
  1368 	var testEl = makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="bar" itemscope>st</span> ing');
  1369 	assert_equals( testEl.itemValue, 'te st ing', 'reading' );
  1370 	testEl.innerHTML = 're<strong>te</strong>st';
  1371 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1372 	testEl.itemValue = 'test';
  1373 	assert_equals( testEl.textContent, 'test', 'writing' );
  1374 }, 'itemValue must reflect the textContent of unknown elements');
  1375 test(function () {
  1376 	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');
  1377 	assert_equals( testEl.itemValue, 'te st ing', 'reading' );
  1378 	testEl.innerHTML = 're<strong>te</strong>st';
  1379 	assert_equals( testEl.itemValue, 'retest', 'reading after change' );
  1380 	testEl.itemValue = 'test';
  1381 	assert_equals( testEl.textContent, 'test', 'writing' );
  1382 }, 'itemValue must reflect the textContent of unknown elements with known attributes');
  1383 test(function () {
  1384 	var testEl = makeEl('input',{itemprop:'foo',value:'test'});
  1385 	assert_equals( testEl.itemValue, '', 'reading' );
  1386 	testEl.value = 'retest';
  1387 	assert_equals( testEl.itemValue, '', 'reading after change' );
  1388 }, 'itemValue must not reflect the value of input elements');
  1389 test(function () {
  1390 	var testEl, eltypes = [
  1391 		makeEl('meta',{itemprop:'foo',content:'test'}),
  1392 		makeEl('audio',{itemprop:'foo',src:'test'},'fail'),
  1393 		makeEl('embed',{itemprop:'foo',src:'test'}),
  1394 		makeEl('iframe',{itemprop:'foo',src:'test'},'fail'),
  1395 		makeEl('img',{itemprop:'foo',src:'test'}),
  1396 		makeEl('source',{itemprop:'foo',src:'test'}),
  1397 		makeEl('track',{itemprop:'foo',src:'test'}),
  1398 		makeEl('video',{itemprop:'foo',src:'test'},'fail'),
  1399 		makeEl('a',{itemprop:'foo',href:'test'},'fail'),
  1400 		makeEl('area',{itemprop:'foo',href:'test'}),
  1401 		makeEl('link',{itemprop:'foo',href:'test'}),
  1402 		makeEl('object',{itemprop:'foo',data:'test'},'fail'),
  1403 		makeEl('time',{itemprop:'foo'},'fail'),
  1404 		makeEl('time',{itemprop:'foo',datetime:'test'},'fail'),
  1405 		makeEl('div',{itemprop:'foo'},'test'),
  1406 		makeEl('madeuponthespot',{itemprop:'foo'},'test'),
  1407 		makeEl('madeuponthespot',{itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test'),
  1408 		makeEl('input',{itemprop:'foo',value:'test'},'test')
  1409 	], beforeValues, i;
  1410 	for( i = 0; i < eltypes.length; i++ ) {
  1411 		testEl = eltypes[i];
  1412 		beforeValues = testEl.itemValue;
  1413 		testEl.itemScope = true;
  1414 		assert_equals( testEl.itemValue, testEl, 'itemscope enabled on '+testEl.tagName+' index '+i );
  1415 		testEl.itemScope = false;
  1416 		assert_equals( testEl.itemValue, beforeValues, 'itemscope disabled on '+testEl.tagName+' index '+i );
  1417 		testEl.itemScope = true;
  1418 		testEl.removeAttribute('itemscope');
  1419 		assert_equals( testEl.itemValue, beforeValues, 'itemscope attribute removed on '+testEl.tagName+' index '+i );
  1421 }, 'dynamic changes of itemscope should change the value exposed through itemValue');
  1423 test(function () {
  1424 	var testEl, eltypes = [
  1425 		makeEl('meta',{itemprop:'foo',content:'test'}),
  1426 		makeEl('audio',{itemprop:'foo',src:'test'},'fail'),
  1427 		makeEl('embed',{itemprop:'foo',src:'test'}),
  1428 		makeEl('iframe',{itemprop:'foo',src:'test'},'fail'),
  1429 		makeEl('img',{itemprop:'foo',src:'test'}),
  1430 		makeEl('source',{itemprop:'foo',src:'test'}),
  1431 		makeEl('track',{itemprop:'foo',src:'test'}),
  1432 		makeEl('video',{itemprop:'foo',src:'test'},'fail'),
  1433 		makeEl('a',{itemprop:'foo',href:'test'},'fail'),
  1434 		makeEl('area',{itemprop:'foo',href:'test'}),
  1435 		makeEl('link',{itemprop:'foo',href:'test'}),
  1436 		makeEl('object',{itemprop:'foo',data:'test'},'fail'),
  1437 		makeEl('time',{itemprop:'foo'},'fail'),
  1438 		makeEl('time',{itemprop:'foo',datetime:'test'},'fail'),
  1439 		makeEl('div',{itemprop:'foo'},'test'),
  1440 		makeEl('madeuponthespot',{itemprop:'foo'},'test'),
  1441 		makeEl('madeuponthespot',{itemprop:'foo',content:'test',src:'test',href:'test',data:'test',datetime:'test',value:'test'},'test'),
  1442 		makeEl('input',{itemprop:'foo',value:'test'},'test')
  1443 	], beforeValues, i;
  1444 	for( i = 0; i < eltypes.length; i++ ) {
  1445 		testEl = eltypes[i];
  1446 		beforeValues = testEl.itemValue;
  1447 		testEl.itemProp.remove('foo');
  1448 		assert_equals( testEl.itemValue, beforeValues, 'itemprop tokens removed on '+testEl.tagName+' index '+i );
  1449 		testEl.removeAttribute('itemprop');
  1450 		assert_equals( testEl.itemValue, null, 'itemprop attribute removed on '+testEl.tagName+' index '+i );
  1451 		testEl.itemProp.toggle('foo');
  1452 		assert_equals( testEl.itemValue, beforeValues, 'itemprop tokens added on '+testEl.tagName+' index '+i );
  1454 }, 'dynamic changes of itemprop should change the value exposed through itemValue');
  1456 /* properties */
  1457 test(function () {
  1458 	assert_equals( typeof makeEl('div',{}).properties, 'object' );
  1459 }, 'the properties property must be an object');
  1460 test(function () {
  1461 	var testEl = makeEl('div',{});
  1462 	assert_true( testEl.properties instanceof HTMLPropertiesCollection, 'instanceof HTMLPropertiesCollection' );
  1463 	assert_true( testEl.properties instanceof HTMLCollection, 'instanceof HTMLCollection' );
  1464 	HTMLPropertiesCollection.prototype.customProperty = true;
  1465 	HTMLCollection.prototype.anotherCustomProperty = true;
  1466 	assert_true( testEl.properties.customProperty, 'inheritance from HTMLPropertiesCollection' );
  1467 	assert_true( testEl.properties.anotherCustomProperty, 'inheritance from HTMLCollection' );
  1468 	HTMLPropertiesCollection.prototype.anotherCustomProperty = false;
  1469 	assert_false( testEl.properties.anotherCustomProperty, 'shadowing by HTMLPropertiesCollection' );
  1470 }, 'the properties property must implement HTMLPropertiesCollection and HTMLCollection');
  1471 test(function () {
  1472 	var failed = false, elem = makeEl('div',{itemscope:'itemscope'}), realList = elem.properties;
  1473 	try {
  1474 		elem.properties = '';
  1475 	} catch(e) {
  1476 		failed = e;
  1478 	assert_equals(elem.properties,realList);
  1479 	assert_false(failed,'an error was thrown');
  1480 }, 'the properties property must be read-only');
  1481 test(function () {
  1482 	var testEl = makeEl('div',{});
  1483 	assert_equals( testEl.properties, testEl.properties );
  1484 }, 'the properties property must always reference the same object');
  1485 test(function () {
  1486 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  1487 	assert_equals( testEl.properties.length, 0, 'length' );
  1488 	assert_true( !testEl.properties.item(0), 'item(0)' );
  1489 	assert_true( !testEl.properties[0], '[0]' );
  1490 	assert_equals( testEl.properties.namedItem('foo').length, 0, 'namedItem' );
  1491 	assert_true( !testEl.properties['foo'], '[namedItem]' );
  1492 	assert_equals( testEl.properties.namedItem('foo').getValues().length, 0, 'namedItem' );
  1493 	assert_equals( testEl.properties.names.length, 0, 'names' );
  1494 }, 'the properties collection must be empty if the element does not have an itemscope property');
  1495 test(function() {
  1496 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  1497 	assert_throws( new TypeError(), function() { testEl.properties('foo'); } );
  1498 	assert_throws( new TypeError(), function() { testEl.properties(0); } );
  1499 }, 'the properties collection must not support legacycaller');	
  1500 test(function () {
  1501 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  1502 	testEl.itemScope = true;
  1503 	assert_equals( testEl.properties.length, 1, 'length' );
  1504 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'item(0)' );
  1505 	assert_equals( testEl.properties[0], testEl.firstChild, '[0]' );
  1506 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'namedItem' );
  1507 	assert_equals( testEl.properties['foo'].length, 1, '[namedItem]' );
  1508 	assert_equals( testEl.properties.namedItem('foo').getValues().length, 1, 'namedItem' );
  1509 	assert_equals( testEl.properties.names.length, 1, 'names' );
  1510 }, 'the properties collection must become populated if the element is given an itemscope property');
  1511 test(function () {
  1512 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
  1513 	testEl.itemScope = false;
  1514 	assert_equals( testEl.properties.length, 0, 'length' );
  1515 	assert_true( !testEl.properties.item(0), 'item(0)' );
  1516 	assert_true( !testEl.properties[0], '[0]' );
  1517 	assert_equals( testEl.properties.namedItem('foo').length, 0, 'namedItem' );
  1518 	assert_true( !testEl.properties['foo'], '[namedItem]' );
  1519 	assert_equals( testEl.properties.namedItem('foo').getValues().length, 0, 'namedItem' );
  1520 	assert_equals( testEl.properties.names.length, 0, 'names' );
  1521 }, 'the properties collection must become empty if the element\'s itemscope property is removed');
  1522 //properties.item and properties.length (part 1)
  1523 test(function () {
  1524 	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>');
  1525 	assert_equals( testEl.properties.length, 5 );
  1526 }, 'properties.length must be the total number of properties');
  1527 test(function () {
  1528 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
  1529 	assert_equals( testEl.properties.item(0), testEl.childNodes[0], 'item(0)' );
  1530 	assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'item(1)' );
  1531 	assert_equals( testEl.properties.item(2), testEl.childNodes[1].childNodes[0], 'item(2)' );
  1532 	assert_equals( testEl.properties.item(3), testEl.childNodes[2], 'item(3)' );
  1533 }, 'properties.item must give each property in tree order');
  1534 test(function () {
  1535 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
  1536 	testEl.properties.something = "another";
  1537 	var names = Object.getOwnPropertyNames(testEl.properties);
  1538 	assert_array_equals( names, ["0", "1", "2", "3", "foo", "bar", "baz", "qux", "something"] );
  1539 }, 'properties.item must have the right property names on it when enumerated');
  1540 test(function () {
  1541 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
  1542 	assert_equals( testEl.properties.item(4), null, 'positive index' );
  1543 	assert_equals( testEl.properties.item(-1), null, 'negative index' );
  1544 }, 'properties.item must give null for out of range index');
  1545 test(function () {
  1546 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
  1547 	assert_equals( testEl.properties[0], testEl.childNodes[0], '[0]' );
  1548 	assert_equals( testEl.properties[1], testEl.childNodes[1], '[1]' );
  1549 	assert_equals( testEl.properties[2], testEl.childNodes[1].childNodes[0], '[2]' );
  1550 	assert_equals( testEl.properties[3], testEl.childNodes[2], '[3]' );
  1551 }, 'properties[index] must give each property in tree order');
  1552 test(function () {
  1553 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="foo"></div></div><div itemprop="baz qux"></div>');
  1554 	assert_equals( testEl.properties[4], window.undefined, 'positive index' );
  1555 	assert_equals( testEl.properties[-1], window.undefined, 'negative index' );
  1556 }, 'properties[index] must give undefined for out of range index');
  1557 test(function () {
  1558 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo"><div itemprop="bar"></div></div><div><div itemprop="baz"></div></div>');
  1559 	assert_equals( testEl.properties.length, 2, 'length' );
  1560 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0)' );
  1561 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0]' );
  1562 	assert_equals( testEl.properties.item(1), testEl.childNodes[1].firstChild, 'properties.item(1)' );
  1563 	assert_equals( testEl.properties[1], testEl.childNodes[1].firstChild, 'properties[1]' );
  1564 }, 'properties.item and length must ignore properties of nested items');
  1565 test(function () {
  1566 	//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms
  1567 	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>');
  1568 	var testEl = parEl.childNodes[1];
  1569 	document.body.appendChild(parEl);
  1570 	var propLength = testEl.properties.length;
  1571 	var item0 = testEl.properties.item(0);
  1572 	var square0 = testEl.properties[0];
  1573 	var item1 = testEl.properties.item(1);
  1574 	var square1 = testEl.properties[1];
  1575 	var item2 = testEl.properties.item(2);
  1576 	var square2 = testEl.properties[2];
  1577 	var item3 = testEl.properties.item(3);
  1578 	var square3 = testEl.properties[3];
  1579 	document.body.removeChild(parEl);
  1580 	assert_equals( propLength, 4, 'length' );
  1581 	assert_equals( item0, parEl.firstChild, 'properties.item(0)' );
  1582 	assert_equals( square0, parEl.firstChild, 'properties[0]' );
  1583 	assert_equals( item1, testEl.firstChild, 'properties.item(1)' );
  1584 	assert_equals( square1, testEl.firstChild, 'properties[1]' );
  1585 	assert_equals( item2, parEl.childNodes[2], 'properties.item(2)' );
  1586 	assert_equals( square2, parEl.childNodes[2], 'properties[2]' );
  1587 	assert_equals( item3, parEl.childNodes[2].firstChild, 'properties.item(3)' );
  1588 	assert_equals( square3, parEl.childNodes[2].firstChild, 'properties[3]' );
  1589 }, 'properties.item and length must see items added with itemref when attached to the document\'s DOM');
  1590 test(function () {
  1591 	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>');
  1592 	var testEl = parEl.childNodes[1];
  1593 	assert_equals( testEl.properties.length, 4, 'length' );
  1594 	assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0)' );
  1595 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0]' );
  1596 	assert_equals( testEl.properties.item(1), testEl.firstChild, 'properties.item(1)' );
  1597 	assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1]' );
  1598 	assert_equals( testEl.properties.item(2), parEl.childNodes[2], 'properties.item(2)' );
  1599 	assert_equals( testEl.properties[2], parEl.childNodes[2], 'properties[2]' );
  1600 	assert_equals( testEl.properties.item(3), parEl.childNodes[2].firstChild, 'properties.item(3)' );
  1601 	assert_equals( testEl.properties[3], parEl.childNodes[2].firstChild, 'properties[3]' );
  1602 }, 'properties.item and length must see items added with itemref');
  1603 test(function () {
  1604 	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>');
  1605 	var testEl = parEl.childNodes[0];
  1606 	assert_equals( testEl.properties.length, 2, 'length' );
  1607 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
  1608 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
  1609 	document.body.appendChild(parEl)
  1610 	var length = testEl.properties.length;
  1611 	var item0 = testEl.properties.item(0);
  1612 	var item1 = testEl.properties.item(0);
  1613 	document.body.removeChild(parEl)
  1614 	assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
  1615 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
  1616 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
  1617 }, 'itemref must reference the first element with a given ID');
  1618 test(function () {
  1619 	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>');
  1620 	var testEl = parEl.childNodes[0];
  1621 	assert_equals( testEl.properties.length, 2, 'length' );
  1622 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
  1623 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
  1624 	document.body.appendChild(parEl)
  1625 	var length = testEl.properties.length;
  1626 	var item0 = testEl.properties.item(0);
  1627 	var item1 = testEl.properties.item(0);
  1628 	document.body.removeChild(parEl)
  1629 	assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
  1630 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
  1631 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
  1632 }, 'itemref must ignore duplicated IDs');
  1633 test(function () {
  1634 	var parEl = makeEl('div',{},'<div itemscope itemref="id0 id1"></div><div itemprop="foo" id="id1"><div itemprop="bar"></div></div>');
  1635 	var testEl = parEl.childNodes[0];
  1636 	assert_equals( testEl.properties.length, 2, 'length' );
  1637 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0)' );
  1638 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1)' );
  1639 	document.body.appendChild(parEl)
  1640 	var length = testEl.properties.length;
  1641 	var item0 = testEl.properties.item(0);
  1642 	var item1 = testEl.properties.item(0);
  1643 	document.body.removeChild(parEl)
  1644 	assert_equals( testEl.properties.length, 2, 'length (attached to document)' );
  1645 	assert_equals( testEl.properties.item(0), parEl.childNodes[1], 'properties.item(0) (attached to document)' );
  1646 	assert_equals( testEl.properties.item(1), parEl.childNodes[1].firstChild, 'properties.item(1) (attached to document)' );
  1647 }, 'itemref must ignore non-existent IDs');
  1648 test(function () {
  1649 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
  1650 	var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
  1651 	assert_equals( testEl.properties.length, 0 );
  1652 }, 'itemref in a dislocated tree must not reference elements from another dislocated tree');
  1653 test(function () {
  1654 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
  1655 	var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
  1656 	document.body.appendChild(dummyEl);
  1657 	var tmp = testEl.properties.length;
  1658 	document.body.removeChild(dummyEl);
  1659 	assert_equals( tmp, 0 );
  1660 }, 'itemref in a dislocated tree must not reference elements from the main document');
  1661 test(function () {
  1662 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'});
  1663 	var dummyEl = makeEl('div',{id:'id1',itemprop:'foo'});
  1664 	document.body.appendChild(testEl);
  1665 	var tmp = testEl.properties.length;
  1666 	document.body.removeChild(testEl);
  1667 	assert_equals( tmp, 0 );
  1668 }, 'itemref in the main document must not reference elements from a dislocated tree');
  1669 test(function () {
  1670 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  1671 	assert_equals( testEl.properties.length, 1, 'length (before test)' );
  1672 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (before test)' );
  1673 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
  1674 	testEl.appendChild(makeEl('div',{itemprop:'bar'}));
  1675 	assert_equals( testEl.properties.length, 2, 'length after adding a child' );
  1676 	assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) after adding a child' );
  1677 	assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] after adding a child' );
  1678 	testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
  1679 	assert_equals( testEl.properties.length, 3, 'length after adding a child with duplicated name' );
  1680 	assert_equals( testEl.properties.item(2), testEl.childNodes[1].firstChild, 'properties.item(2) after adding a child with duplicated name' );
  1681 	assert_equals( testEl.properties[2], testEl.childNodes[1].firstChild, 'properties[2] after adding a child with duplicated name' );
  1682 	testEl.lastChild.removeChild(testEl.lastChild.firstChild);
  1683 	assert_equals( testEl.properties.length, 2, 'length after removing a child' );
  1684 	assert_true( !testEl.properties.item(2), 'properties.item(1) after removing a child' );
  1685 	assert_true( !testEl.properties[2], 'properties[1] after removing a child' );
  1686 }, 'properties.item and length must update when adding property elements');
  1687 test(function () {
  1688 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
  1689 	assert_equals( testEl.properties.length, 2, 'length (before test)' );
  1690 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (before test)' );
  1691 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
  1692 	assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) (before test)' );
  1693 	assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] (before test)' );
  1694 	testEl.appendChild(testEl.firstChild);
  1695 	assert_equals( testEl.properties.length, 2, 'length (after test)' );
  1696 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) (after test)' );
  1697 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (after test)' );
  1698 	assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) (after test)' );
  1699 	assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] (after test)' );
  1700 }, 'properties.item must update when re-ordering property elements, but length must not');
  1701 test(function () {
  1702 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
  1703 	assert_equals( testEl.properties.length, 1, 'length (before test)' );
  1704 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] (before test)' );
  1705 	testEl.lastChild.itemProp.toggle('bar');
  1706 	assert_equals( testEl.properties.length, 2, 'length (after test 1)' );
  1707 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) after adding a token' );
  1708 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] after adding a token' );
  1709 	assert_equals( testEl.properties.item(1), testEl.childNodes[1], 'properties.item(1) after adding a token' );
  1710 	assert_equals( testEl.properties[1], testEl.childNodes[1], 'properties[1] after adding a token' );
  1711 	testEl.lastChild.removeAttribute('itemprop');
  1712 	assert_equals( testEl.properties.length, 1, 'length after removing an attribute' );
  1713 	assert_equals( testEl.properties.item(0), testEl.firstChild, 'properties.item(0) after removing an attribute' );
  1714 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] after removing an attribute' );
  1715 	assert_true( !testEl.properties.item(1), 'properties.item(1) after removing an attribute' );
  1716 	assert_true( !testEl.properties[1], 'properties[1] after removing an attribute' );
  1717 }, 'properties.item and length must update when changing itemProp of children');
  1718 test(function () {
  1719 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
  1720 	var testEl = parEl.childNodes[1];
  1721 	assert_equals( testEl.properties.length, 0, 'length (before test)' );
  1722 	parEl.firstChild.id = 'id1';
  1723 	assert_equals( testEl.properties.length, 2, 'length after id is created' );
  1724 	assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after id is created' );
  1725 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after id is created' );
  1726 	assert_equals( testEl.properties.item(1), parEl.firstChild.firstChild, 'properties.item(1) after id is created' );
  1727 	assert_equals( testEl.properties[1], parEl.firstChild.firstChild, 'properties[1] after id is created' );
  1728 	parEl.firstChild.removeAttribute('id');
  1729 	assert_equals( testEl.properties.length, 0, 'length after removing an attribute' );
  1730 	assert_true( !testEl.properties.item(0), 'properties.item(0) after removing an attribute' );
  1731 	assert_true( !testEl.properties[0], 'properties[0] after removing an attribute' );
  1732 	document.body.appendChild(parEl);
  1733 	var beflength = testEl.properties.length;
  1734 	parEl.firstChild.id = 'id1';
  1735 	var length1 = testEl.properties.length,
  1736 	    item0 = testEl.properties.item(0),
  1737 	    prop0 = testEl.properties[0],
  1738 	    item1 = testEl.properties.item(1),
  1739 	    prop1 = testEl.properties[1];
  1740 	parEl.firstChild.removeAttribute('id');
  1741 	var length2 = testEl.properties.length,
  1742 	    bitem = !testEl.properties.item(0),
  1743 	    bprop = !testEl.properties[0];
  1744 	document.body.removeChild(parEl);
  1745 	assert_equals( beflength, 0, 'length (before test) when appended to document' );
  1746 	assert_equals( length1, 2, 'length after id is created when appended to document' );
  1747 	assert_equals( item0, parEl.firstChild, 'properties.item(0) after id is created when appended to document' );
  1748 	assert_equals( prop0, parEl.firstChild, 'properties[0] after id is created when appended to document' );
  1749 	assert_equals( item1, parEl.firstChild.firstChild, 'properties.item(1) after id is created when appended to document' );
  1750 	assert_equals( prop1, parEl.firstChild.firstChild, 'properties[1] after id is created when appended to document' );
  1751 	assert_equals( length2, 0, 'length after removing an attribute when appended to document' );
  1752 	assert_true( bitem, 'properties.item(0) after removing an attribute when appended to document' );
  1753 	assert_true( bprop, 'properties[0] after removing an attribute when appended to document' );
  1754 }, 'properties.item and length must update when changing id of referenced sibling');
  1755 test(function () {
  1756 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
  1757 	var testEl = parEl.childNodes[1];
  1758 	assert_equals( testEl.properties.length, 1, 'length (before test)' );
  1759 	assert_equals( testEl.properties.item(0), parEl.lastChild, 'properties.item(0) (before test)' );
  1760 	assert_equals( testEl.properties[0], parEl.lastChild, 'properties[0] (before test)' );
  1761 	parEl.firstChild.id = 'id1';
  1762 	assert_equals( testEl.properties.length, 2, 'length after id is created' );
  1763 	assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after id is created' );
  1764 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after id is created' );
  1765 	assert_equals( testEl.properties.item(1), parEl.firstChild.firstChild, 'properties.item(1) after id is created' );
  1766 	assert_equals( testEl.properties[1], parEl.firstChild.firstChild, 'properties[1] after id is created' );
  1767 	parEl.firstChild.removeAttribute('id');
  1768 	assert_equals( testEl.properties.length, 1, 'length after removing an attribute' );
  1769 	assert_equals( testEl.properties.item(0), parEl.lastChild, 'properties.item(0) after removing an attribute' );
  1770 	assert_equals( testEl.properties[0], parEl.lastChild, 'properties[0] after removing an attribute' );
  1771 	document.body.appendChild(parEl);
  1772 	var beflength = testEl.properties.length,
  1773 	    befitem = testEl.properties.item(0),
  1774 	    befprop = testEl.properties[0];
  1775 	parEl.firstChild.id = 'id1';
  1776 	var length1 = testEl.properties.length,
  1777 	    item0 = testEl.properties.item(0),
  1778 	    prop0 = testEl.properties[0],
  1779 	    item1 = testEl.properties.item(1),
  1780 	    prop1 = testEl.properties[1];
  1781 	parEl.firstChild.removeAttribute('id');
  1782 	var length2 = testEl.properties.length,
  1783 	    afitem = testEl.properties.item(0),
  1784 	    afprop = testEl.properties[0];
  1785 	document.body.removeChild(parEl);
  1786 	assert_equals( beflength, 1, 'length (before test) when appended to document' );
  1787 	assert_equals( befitem, parEl.lastChild, 'properties.item(0) (before test)' );
  1788 	assert_equals( befprop, parEl.lastChild, 'properties[0] (before test)' );
  1789 	assert_equals( length1, 2, 'length after id is created when appended to document' );
  1790 	assert_equals( item0, parEl.firstChild, 'properties.item(0) after id is created when appended to document' );
  1791 	assert_equals( prop0, parEl.firstChild, 'properties[0] after id is created when appended to document' );
  1792 	assert_equals( item1, parEl.firstChild.firstChild, 'properties.item(1) after id is created when appended to document' );
  1793 	assert_equals( prop1, parEl.firstChild.firstChild, 'properties[1] after id is created when appended to document' );
  1794 	assert_equals( length2, 1, 'length after removing an attribute when appended to document' );
  1795 	assert_equals( afitem, parEl.lastChild, 'properties.item(0) after removing an attribute when appended to document' );
  1796 	assert_equals( afprop, parEl.lastChild, 'properties[0] after removing an attribute when appended to document' );
  1797 }, 'properties.item and length must update when changing duplicated id of referenced sibling');
  1798 test(function () {
  1799 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
  1800 	var testEl = parEl.childNodes[1];
  1801 	assert_equals( testEl.properties.length, 0, 'length (before test)' );
  1802 	testEl.itemRef.toggle('id1');
  1803 	assert_equals( testEl.properties.length, 1, 'length after itemref is changed' );
  1804 	assert_equals( testEl.properties.item(0), parEl.firstChild, 'properties.item(0) after itemref is changed' );
  1805 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after itemref is changed' );
  1806 	testEl.removeAttribute('itemref');
  1807 	assert_equals( testEl.properties.length, 0, 'length after itemref is removed' );
  1808 	assert_true( !testEl.properties.item(0), 'properties.item(0) itemref is removed' );
  1809 	assert_true( !testEl.properties[0], 'properties[0] itemref is removed' );
  1810 	document.body.appendChild(parEl);
  1811 	var beflength = testEl.properties.length;
  1812 	testEl.itemRef.toggle('id1');
  1813 	var length1 = testEl.properties.length,
  1814 	    item0 = testEl.properties.item(0),
  1815 	    prop0 = testEl.properties[0];
  1816 	testEl.removeAttribute('itemref');
  1817 	var length2 = testEl.properties.length,
  1818 	    bitem = !testEl.properties.item(0),
  1819 	    bprop = !testEl.properties[0];
  1820 	document.body.removeChild(parEl);
  1821 	assert_equals( beflength, 0, 'length (before test) when appended to document' );
  1822 	assert_equals( length1, 1, 'length after itemref is changed when appended to document' );
  1823 	assert_equals( item0, parEl.firstChild, 'properties.item(0) after itemref is changed when appended to document' );
  1824 	assert_equals( prop0, parEl.firstChild, 'properties[0] after itemref is changed when appended to document' );
  1825 	assert_equals( length2, 0, 'length after itemref is removed when appended to document' );
  1826 	assert_true( bitem, 'properties.item(0) after itemref is removed when appended to document' );
  1827 	assert_true( bprop, 'properties[0] after itemref is removed when appended to document' );
  1828 }, 'properties.item and length must update when changing itemref to point to an element');
  1829 test(function () {
  1830 	var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
  1831 	var testEl = parEl.childNodes[1];
  1832 	assert_equals( testEl.properties.length, 0, 'length (before test)' );
  1833 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  1834 	assert_equals( testEl.properties.length, 1, 'length after a referenced element is added' );
  1835 	assert_equals( testEl.properties.item(0), parEl.firstChild.lastChild, 'properties.item(0) after a referenced element is added' );
  1836 	assert_equals( testEl.properties[0], parEl.firstChild.lastChild, 'properties[0] after a referenced element is added' );
  1837 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  1838 	assert_equals( testEl.properties.length, 2, 'length after a referenced itemprop is changed' );
  1839 	assert_equals( testEl.properties.item(0), parEl.firstChild.firstChild, 'properties.item(0) after a referenced itemprop is changed' );
  1840 	assert_equals( testEl.properties[0], parEl.firstChild.firstChild, 'properties[0] after a referenced itemprop is changed' );
  1841 	assert_equals( testEl.properties.item(1), parEl.firstChild.lastChild, 'properties.item(1) after a referenced itemprop is changed' );
  1842 	assert_equals( testEl.properties[1], parEl.firstChild.lastChild, 'properties[1] after a referenced itemprop is changed' );
  1843 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  1844 	assert_equals( testEl.properties.length, 1, 'length after a referenced element is removed' );
  1845 	assert_equals( testEl.properties.item(0), parEl.firstChild.firstChild, 'properties.item(0) after a referenced element is removed' );
  1846 	assert_equals( testEl.properties[0], parEl.firstChild.firstChild, 'properties[0] after a referenced element is removed' );
  1847 	assert_true( !testEl.properties.item(1), 'properties.item(1) after a referenced element is removed' );
  1848 	assert_true( !testEl.properties[1], 'properties[1] after a referenced element is removed' );
  1849 	parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
  1850 	testEl = parEl.childNodes[1];
  1851 	document.body.appendChild(parEl);
  1852 	var beflength = testEl.properties.length;
  1853 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  1854 	var length1 = testEl.properties.length,
  1855 	    item0a = testEl.properties.item(0),
  1856 	    prop0a = testEl.properties[0],
  1857 	    targ0a = parEl.firstChild.lastChild;
  1858 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  1859 	var length2 = testEl.properties.length,
  1860 	    item0b = testEl.properties.item(0),
  1861 	    prop0b = testEl.properties[0];
  1862 	    item1b = testEl.properties.item(1),
  1863 	    prop1b = testEl.properties[1],
  1864 	    targ0b = parEl.firstChild.firstChild,
  1865 	    targ1b = parEl.firstChild.lastChild;
  1866 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  1867 	var length3 = testEl.properties.length,
  1868 	    item0c = testEl.properties.item(0),
  1869 	    prop0c = testEl.properties[0];
  1870 	    item1c = testEl.properties.item(1),
  1871 	    prop1c = testEl.properties[1],
  1872 	    targ0c = parEl.firstChild.firstChild;
  1873 	document.body.removeChild(parEl);
  1874 	assert_equals( beflength, 0, 'length (before test) when appended to document' );
  1875 	assert_equals( length1, 1, 'length after a referenced element is added when appended to document' );
  1876 	assert_equals( item0a, targ0a, 'properties.item(0) after a referenced element is added when appended to document' );
  1877 	assert_equals( prop0a, targ0a, 'properties[0] after a referenced element is added when appended to document' );
  1878 	assert_equals( length2, 2, 'length after a referenced itemprop is changed when appended to document' );
  1879 	assert_equals( item0b, targ0b, 'properties.item(0) after a referenced itemprop is changed when appended to document' );
  1880 	assert_equals( prop0b, targ0b, 'properties[0] after a referenced itemprop is changed when appended to document' );
  1881 	assert_equals( item1b, targ1b, 'properties.item(1) after a referenced itemprop is changed when appended to document' );
  1882 	assert_equals( prop1b, targ1b, 'properties[1] after a referenced itemprop is changed when appended to document' );
  1883 	assert_equals( length3, 1, 'length after a referenced element is removed when appended to document' );
  1884 	assert_equals( item0c, targ0c, 'properties.item(0) after a referenced element is removed when appended to document' );
  1885 	assert_equals( prop0c, targ0c, 'properties[0] after a referenced element is removed when appended to document' );
  1886 	assert_true( !item1c, 'properties.item(1) after a referenced element is removed when appended to document' );
  1887 	assert_true( !prop1c, 'properties[1] after a referenced element is removed when appended to document' );
  1888 }, 'properties.item and length must update when changing children of elements referenced through itemref');
  1889 test(function () {
  1890 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="foo"></div></div>');
  1891 	var testEl = parEl.childNodes[1];
  1892 	assert_equals( testEl.properties.length, 2, 'length (before test)' );
  1893 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] (before test)' );
  1894 	assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] (before test)' );
  1895 	document.body.appendChild(testEl);
  1896 	var step1length = testEl.properties.length;
  1897 	var step1prop0 = testEl.properties[0];
  1898 	var step1prop1 = testEl.properties[1];
  1899 	parEl.appendChild(testEl);
  1900 	assert_equals( step1length, 1, 'length after changing parent' );
  1901 	assert_equals( step1prop0, testEl.firstChild, 'properties[0] after changing parent' );
  1902 	assert_true( !step1prop1, 'properties[1] after changing parent' );
  1903 	assert_equals( testEl.properties.length, 2, 'length after re-parenting' );
  1904 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] after re-parenting' );
  1905 	assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] after re-parenting' );
  1906 	document.body.appendChild(parEl);
  1907 	var step2length = testEl.properties.length;
  1908 	var step2prop0 = testEl.properties[0];
  1909 	var step2prop1 = testEl.properties[1];
  1910 	document.createElement('div').appendChild(testEl);
  1911 	var step3length = testEl.properties.length;
  1912 	var step3prop0 = testEl.properties[0];
  1913 	var step3prop1 = testEl.properties[1];
  1914 	parEl.appendChild(testEl);
  1915 	var step4length = testEl.properties.length;
  1916 	var step4prop0 = testEl.properties[0];
  1917 	var step4prop1 = testEl.properties[1];
  1918 	document.body.removeChild(parEl);
  1919 	assert_equals( step2length, 2, 'length (before test) when appended to document' );
  1920 	assert_equals( step2prop0, parEl.firstChild, 'properties[0] (before test) when appended to document' );
  1921 	assert_equals( step2prop1, testEl.firstChild, 'properties[1] (before test) when appended to document' );
  1922 	assert_equals( step3length, 1, 'length after changing parent when appended to document' );
  1923 	assert_equals( step3prop0, testEl.firstChild, 'properties[0] after changing parent when appended to document' );
  1924 	assert_true( !step3prop1, 'properties[1] after changing parent when appended to document' );
  1925 	assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
  1926 	assert_equals( step4prop0, parEl.firstChild, 'properties[0] after re-parenting when appended to document' );
  1927 	assert_equals( step4prop1, testEl.firstChild, 'properties[1] after re-parenting when appended to document' );
  1928 }, 'properties.item and length must update when appending elements with itemref to different parents');
  1929 test(function () {
  1930 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
  1931 	assert_equals( testEl.properties.length, 1, 'length (before test)' );
  1932 	assert_equals( testEl.properties.item(0), testEl.firstChild.firstChild, 'properties.item(0) (before test)' );
  1933 	assert_equals( testEl.properties[0], testEl.firstChild.firstChild, 'properties[0] (before test)' );
  1934 	testEl.firstChild.itemScope = true;
  1935 	assert_equals( testEl.properties.length, 0, 'length after setting itemscope' );
  1936 	assert_true( !testEl.properties.item(0), 'properties.item(0) after setting itemscope' );
  1937 	assert_true( !testEl.properties[0], 'properties[0] after setting itemscope' );
  1938 	testEl.firstChild.removeAttribute('itemscope');
  1939 	assert_equals( testEl.properties.length, 1, 'length after removing itemscope attribute' );
  1940 	assert_equals( testEl.properties.item(0), testEl.firstChild.firstChild, 'properties.item(0) after removing itemscope attribute' );
  1941 	assert_equals( testEl.properties[0], testEl.firstChild.firstChild, 'properties[0] after removing itemscope attribute' );
  1942 }, 'properties.item and length must update when changing itemscope of children');
  1943 //properties.namedItem
  1944 test(function () {
  1945 	assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo'), 'object' );
  1946 }, 'the namedItem must return an object');
  1947 test(function () {
  1948 	assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties['foo'], 'object' );
  1949 }, '.properties[] must also act as .properties.namedItem() when there are matching properties');
  1950 test(function () {
  1951 	assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'').properties.namedItem('foo'), 'object' );
  1952 }, 'the namedItem must return an object even if there are no matching properties');
  1953 test(function () {
  1954 	assert_equals( typeof makeEl('div',{itemscope:'itemscope'},'').properties['foo'], 'undefined' );
  1955 }, '.properties[] must return undefined when no property exists with the given name');
  1956 test(function () {
  1957 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  1958 	var PNL = testEl.properties.namedItem('foo');
  1959 	assert_equals( PNL, testEl.properties.namedItem('foo'), 'before modification' );
  1960 	testEl.innerHTML = '';
  1961 	assert_equals( PNL, testEl.properties.namedItem('foo'), 'after modification' );
  1962 }, 'namedItem must return the same object for the same property name');
  1963 test(function () {
  1964 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  1965 	assert_false( testEl.properties.namedItem('foo') == testEl.properties.namedItem('bar') );
  1966 }, 'namedItem must return a different object for a different property name');
  1967 test(function () {
  1968 	assert_false( makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo') == makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>').properties.namedItem('foo') );
  1969 }, 'namedItem must return a different object for different elements with the same property name');
  1970 test(function () {
  1971 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  1972 	assert_equals( testEl.properties.namedItem('foo'), testEl.properties['foo'] );
  1973 }, 'namedItem() and properties[] must return the same object for the same property name');
  1974 test(function () {
  1975 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  1976 	assert_true( testEl.properties.namedItem('foo') instanceof PropertyNodeList, 'instanceof PropertyNodeList' );
  1977 	assert_true( testEl.properties.namedItem('foo') instanceof NodeList, 'instanceof NodeList' );
  1978 	PropertyNodeList.prototype.customProperty = true;
  1979 	NodeList.prototype.anotherCustomProperty = true;
  1980 	assert_true( testEl.properties.namedItem('foo').customProperty, 'inheritance from PropertyNodeList' );
  1981 	assert_true( testEl.properties.namedItem('foo').anotherCustomProperty, 'inheritance from NodeList' );
  1982 	PropertyNodeList.prototype.anotherCustomProperty = false;
  1983 	assert_false( testEl.properties.anotherCustomProperty, 'shadowing by PropertyNodeList' );
  1984 }, 'the properties property must implement PropertyNodeList and NodeList');
  1985 test(function () {
  1986 	var failed = false, elem = makeEl('div',{itemscope:'itemscope'});
  1987 	try {
  1988 		elem.properties.namedItem = 'pass';
  1989 	} catch(e) {
  1990 		failed = e;
  1992 	assert_equals(elem.properties.namedItem,'pass');
  1993 	assert_false(failed,'an error was thrown');
  1994 }, 'the namedItem property must be read/write');
  1995 test(function () {
  1996 	//also tests for sort ordering, which is fairly simple in this case
  1997 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"><div itemprop="baz qux"></div></div><div itemprop="foo"></div>');
  1998 	assert_equals( testEl.properties.namedItem('foo').length, 2, 'length of foo' );
  1999 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'length of bar' );
  2000 	assert_equals( testEl.properties.namedItem('baz').length, 1, 'length of baz' );
  2001 	assert_equals( testEl.properties.namedItem('qux').length, 1, 'length of qux' );
  2002 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'first foo' );
  2003 	assert_equals( testEl.properties.namedItem('foo')[1], testEl.lastChild, 'last foo' );
  2004 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.childNodes[1], 'bar' );
  2005 	assert_equals( testEl.properties.namedItem('baz')[0], testEl.childNodes[1].firstChild, 'baz' );
  2006 	assert_equals( testEl.properties.namedItem('qux')[0], testEl.childNodes[1].firstChild, 'qux' );
  2007 }, 'PropertyNodeList must contain the correct properties');
  2008 test(function () {
  2009 	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>');
  2010 	assert_equals( testEl.properties.namedItem('foo').length, 2, 'length of foo' );
  2011 	assert_equals( testEl.properties.namedItem('FOO').length, 2, 'length of FOO' );
  2012 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'first foo' );
  2013 	assert_equals( testEl.properties.namedItem('foo')[1], testEl.childNodes[1].lastChild, 'last foo' );
  2014 	assert_equals( testEl.properties.namedItem('FOO')[0], testEl.childNodes[1].firstChild, 'first FOO' );
  2015 	assert_equals( testEl.properties.namedItem('FOO')[1], testEl.childNodes[1].lastChild, 'last FOO' );
  2016 }, 'PropertyNodeList must be case sensitive');
  2017 test(function () {
  2018 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo bar"></div>');
  2019 	assert_equals( testEl.properties.namedItem('foo bar').length, 0, 'space' );
  2020 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\tbar"></div>');
  2021 	assert_equals( testEl.properties.namedItem('foo\tbar').length, 0, 'tab' );
  2022 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\rbar"></div>');
  2023 	assert_equals( testEl.properties.namedItem('foo\rbar').length, 0, 'carriage return' );
  2024 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\nbar"></div>');
  2025 	assert_equals( testEl.properties.namedItem('foo\nbar').length, 0, 'newline' );
  2026 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo\fbar"></div>');
  2027 	assert_equals( testEl.properties.namedItem('foo\fbar').length, 0, 'formfeed' );
  2028 }, 'namedItem must not match property names containing whitespace');
  2029 test(function () {
  2030 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="|§!&quot;#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_&lt;&gt;帿ŨÆ"></div>');
  2031 	assert_equals( testEl.properties.namedItem('|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>帿ŨÆ').length, 1 );
  2032 }, 'namedItem must match property names containing other special characters');
  2033 test(function () {
  2034 	var testEl = makeEl('div',{itemscope:'itemscope'});
  2035 	var PNL = testEl.properties.namedItem('foo');
  2036 	testEl.innerHTML = '<div itemprop="foo"></div>';
  2037 	assert_equals( PNL.length, 1 );
  2038 	assert_equals( PNL[0], testEl.firstChild );
  2039 }, 'PropertyNodeList must be live');
  2040 test(function () {
  2041 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemscope><div itemprop="foo"></div><div itemprop="bar"></div></div>');
  2042 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'length of foo' );
  2043 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'item 0' );
  2044 	assert_equals( testEl.properties.namedItem('bar').length, 0, 'length of bar' );
  2045 }, 'PropertyNodeList must ignore properties of nested items');
  2046 test(function () {
  2048 	//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms - not that that should make much difference here
  2049 	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>');
  2050 	var testEl = parEl.childNodes[1];
  2051 	document.body.appendChild(parEl);
  2052 	var fooLength = testEl.properties.namedItem('foo').length;
  2053 	var barLength = testEl.properties.namedItem('bar').length;
  2054 	var bazLength = testEl.properties.namedItem('baz').length;
  2055 	var quxLength = testEl.properties.namedItem('qux').length;
  2056 	var foo0 = testEl.properties.namedItem('foo')[0];
  2057 	var foo1 = testEl.properties.namedItem('foo')[1];
  2058 	var bar0 = testEl.properties.namedItem('bar')[0];
  2059 	var baz0 = testEl.properties.namedItem('baz')[0];
  2060 	var qux0 = testEl.properties.namedItem('qux')[0];
  2061 	document.body.removeChild(parEl);
  2062 	assert_equals( fooLength, 2, 'foo length' );
  2063 	assert_equals( barLength, 1, 'bar length' );
  2064 	assert_equals( bazLength, 1, 'baz length' );
  2065 	assert_equals( quxLength, 1, 'qux length' );
  2066 	assert_equals( foo0, parEl.firstChild, 'foo 0' );
  2067 	assert_equals( foo1, testEl.firstChild, 'foo 1' );
  2068 	assert_equals( bar0, testEl.firstChild, 'bar 0' );
  2069 	assert_equals( baz0, parEl.lastChild, 'baz 0' );
  2070 	assert_equals( qux0, parEl.lastChild.firstChild, 'qux 0' );
  2071 }, 'PropertyNodeList must see items added with itemref when attached to the document\'s DOM');
  2072 test(function () {
  2073 	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>');
  2074 	var testEl = parEl.childNodes[1];
  2075 	assert_equals( testEl.properties.namedItem('foo').length, 2, 'foo length' );
  2076 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length' );
  2077 	assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz length' );
  2078 	assert_equals( testEl.properties.namedItem('qux').length, 1, 'qux length' );
  2079 	assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo 0' );
  2080 	assert_equals( testEl.properties.namedItem('foo')[1], testEl.firstChild, 'foo 1' );
  2081 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar 0' );
  2082 	assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz 0' );
  2083 	assert_equals( testEl.properties.namedItem('qux')[0], parEl.lastChild.firstChild, 'qux 0' );
  2084 }, 'PropertyNodeList must see items added with itemref');
  2085 test(function () {
  2086 	//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
  2087 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  2088 	var PNL = testEl.properties.namedItem('foo');
  2089 	testEl.removeAttribute('itemscope');
  2090 	assert_equals( testEl.properties.namedItem('foo').length, 0, 'removing attribute' );
  2091 	assert_equals( PNL.length, 0, 'removing attribute (live)' );
  2092 	assert_true( !testEl.properties['foo'], 'removing attribute []' );
  2093 	testEl.itemScope = true;
  2094 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'setting itemScope' );
  2095 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'property 0 after setting itemScope' );
  2096 	assert_equals( PNL.length, 1, 'setting itemScope (live)' );
  2097 	assert_equals( PNL[0], testEl.firstChild, 'property 0 after setting itemScope (live)' );
  2098 	assert_false( !testEl.properties['foo'], 'setting itemScope []' );
  2099 }, 'PropertyNodeList must update when adding itemscope on the root');
  2100 test(function () {
  2101 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  2102 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length (before test)' );
  2103 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 (before test)' );
  2104 	assert_equals( testEl.properties.namedItem('bar').length, 0, 'bar length (before test)' );
  2105 	testEl.appendChild(makeEl('div',{itemprop:'bar'}));
  2106 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length after adding a child' );
  2107 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 after adding a child' );
  2108 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after adding a child' );
  2109 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'bar 0 after adding a child' );
  2110 	testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2111 	assert_equals( testEl.properties.namedItem('foo').length, 2, 'foo length after adding a child with duplicated name' );
  2112 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'foo 0 after adding a child with duplicated name' );
  2113 	assert_equals( testEl.properties.namedItem('foo')[1], testEl.lastChild.firstChild, 'foo 1 after adding a child with duplicated name' );
  2114 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after adding a child with duplicated name' );
  2115 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'bar 0 after adding a child with duplicated name' );
  2116 	testEl.lastChild.removeChild(testEl.lastChild.firstChild);
  2117 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo length after removing a child' );
  2118 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar length after removing a child' );
  2119 }, 'PropertyNodeList must update when adding property elements');
  2120 test(function () {
  2121 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="foo"></div>');
  2122 	var PNL = testEl.properties.namedItem('foo');
  2123 	assert_equals( PNL[0], testEl.firstChild, 'item 0 (before test)' );
  2124 	assert_equals( PNL[1], testEl.lastChild, 'item 1 (before test)' );
  2125 	testEl.appendChild(testEl.firstChild);
  2126 	assert_equals( PNL[0], testEl.firstChild, 'item 0 (after test)' );
  2127 	assert_equals( PNL[1], testEl.lastChild, 'item 1 (after test)' );
  2128 }, 'PropertyNodeList must update when re-ordering property elements');
  2129 test(function () {
  2130 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
  2131 	var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
  2132 	assert_equals( PNLfoo.length, 1, 'foo length (before test)' );
  2133 	assert_equals( PNLbar.length, 0, 'bar length (before test)' );
  2134 	assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] (before test)' );
  2135 	testEl.lastChild.itemProp.toggle('bar');
  2136 	assert_equals( PNLfoo.length, 1, 'foo length after adding a token' );
  2137 	assert_equals( PNLbar.length, 1, 'bar length after adding a token' );
  2138 	assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after adding a token' );
  2139 	assert_equals( PNLbar[0], testEl.lastChild, 'bar[0] after adding a token' );
  2140 	testEl.lastChild.itemProp.add('foo');
  2141 	assert_equals( PNLfoo.length, 2, 'foo length after adding a duplicated token' );
  2142 	assert_equals( PNLbar.length, 1, 'bar length after adding a duplicated token' );
  2143 	assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after adding a duplicated token' );
  2144 	assert_equals( PNLfoo[1], testEl.lastChild, 'foo[1] after adding a duplicated token' );
  2145 	assert_equals( PNLbar[0], testEl.lastChild, 'bar[0] after adding a duplicated token' );
  2146 	testEl.lastChild.removeAttribute('itemprop');
  2147 	assert_equals( PNLfoo.length, 1, 'foo length after removing an attribute' );
  2148 	assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
  2149 	assert_equals( PNLfoo[0], testEl.firstChild, 'foo[0] after removing an attribute' );
  2150 }, 'PropertyNodeList must update when changing itemProp of children');
  2151 test(function () {
  2152 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
  2153 	var testEl = parEl.childNodes[1];
  2154 	var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
  2155 	assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
  2156 	assert_equals( PNLbar.length, 0, 'bar length (before test)' );
  2157 	parEl.firstChild.id = 'id1';
  2158 	assert_equals( PNLfoo.length, 1, 'foo length after id is created' );
  2159 	assert_equals( PNLbar.length, 1, 'bar length after id is created' );
  2160 	assert_equals( PNLfoo[0], parEl.firstChild, 'foo[0] after id is created' );
  2161 	assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar[0] after id is created' );
  2162 	parEl.firstChild.removeAttribute('id');
  2163 	assert_equals( PNLfoo.length, 0, 'foo length after removing an attribute' );
  2164 	assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
  2165 	document.body.appendChild(parEl);
  2166 	var fooLength0 = PNLfoo.length;
  2167 	var barLength0 = PNLbar.length;
  2168 	parEl.firstChild.id = 'id1';
  2169 	var fooLength1 = PNLfoo.length;
  2170 	var barLength1 = PNLbar.length;
  2171 	var foo0 = PNLfoo[0];
  2172 	var bar0 = PNLbar[0];
  2173 	parEl.firstChild.removeAttribute('id');
  2174 	var fooLength2 = PNLfoo.length;
  2175 	var barLength2 = PNLbar.length;
  2176 	document.body.removeChild(parEl);
  2177 	assert_equals( fooLength0, 0, 'foo length (before test) when appended to document' );
  2178 	assert_equals( barLength0, 0, 'bar length (before test) when appended to document' );
  2179 	assert_equals( fooLength1, 1, 'foo length after id is created when appended to document' );
  2180 	assert_equals( barLength1, 1, 'bar length after id is created when appended to document' );
  2181 	assert_equals( foo0, parEl.firstChild, 'foo[0] after id is created when appended to document' );
  2182 	assert_equals( bar0, parEl.firstChild.firstChild, 'bar[0] after id is created when appended to document' );
  2183 	assert_equals( fooLength2, 0, 'foo length after removing an attribute when appended to document' );
  2184 	assert_equals( barLength2, 0, 'bar length after removing an attribute when appended to document' );
  2185 }, 'PropertyNodeList must update when changing id of referenced sibling');
  2186 test(function () {
  2187 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
  2188 	var testEl = parEl.childNodes[1];
  2189 	var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar'), PNLbaz = testEl.properties.namedItem('baz');
  2190 	assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
  2191 	assert_equals( PNLbar.length, 0, 'bar length (before test)' );
  2192 	assert_equals( PNLbaz.length, 1, 'baz length (before test)' );
  2193 	assert_equals( PNLbaz[0], parEl.lastChild, 'baz[0] (before test)' );
  2194 	parEl.firstChild.id = 'id1';
  2195 	assert_equals( PNLfoo.length, 1, 'foo length after id is created' );
  2196 	assert_equals( PNLbar.length, 1, 'bar length after id is created' );
  2197 	assert_equals( PNLbaz.length, 0, 'baz length after id is created' );
  2198 	assert_equals( PNLfoo[0], parEl.firstChild, 'foo[0] after id is created' );
  2199 	assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar[0] after id is created' );
  2200 	parEl.firstChild.removeAttribute('id');
  2201 	assert_equals( PNLfoo.length, 0, 'foo length after removing an attribute' );
  2202 	assert_equals( PNLbar.length, 0, 'bar length after removing an attribute' );
  2203 	assert_equals( PNLbaz.length, 1, 'baz length after removing an attribute' );
  2204 	assert_equals( PNLbaz[0], parEl.lastChild, 'baz[0] after removing an attribute' );
  2205 	document.body.appendChild(parEl);
  2206 	var fooLength0 = PNLfoo.length;
  2207 	var barLength0 = PNLbar.length;
  2208 	var bazLength0 = PNLbaz.length;
  2209 	var baz0 = PNLbaz[0];
  2210 	parEl.firstChild.id = 'id1';
  2211 	var fooLength1 = PNLfoo.length;
  2212 	var barLength1 = PNLbar.length;
  2213 	var bazLength1 = PNLbaz.length;
  2214 	var foo0 = PNLfoo[0];
  2215 	var bar0 = PNLbar[0];
  2216 	parEl.firstChild.removeAttribute('id');
  2217 	var fooLength2 = PNLfoo.length;
  2218 	var barLength2 = PNLbar.length;
  2219 	var bazLength2 = PNLbaz.length;
  2220 	var baz1 = PNLbaz[0];
  2221 	document.body.removeChild(parEl);
  2222 	assert_equals( fooLength0, 0, 'foo length (before test) when appended to document' );
  2223 	assert_equals( barLength0, 0, 'bar length (before test) when appended to document' );
  2224 	assert_equals( bazLength0, 1, 'baz length (before test)' );
  2225 	assert_equals( baz0, parEl.lastChild, 'baz[0] (before test)' );
  2226 	assert_equals( fooLength1, 1, 'foo length after id is created when appended to document' );
  2227 	assert_equals( barLength1, 1, 'bar length after id is created when appended to document' );
  2228 	assert_equals( bazLength1, 0, 'baz length after id is created' );
  2229 	assert_equals( foo0, parEl.firstChild, 'foo[0] after id is created when appended to document' );
  2230 	assert_equals( bar0, parEl.firstChild.firstChild, 'bar[0] after id is created when appended to document' );
  2231 	assert_equals( fooLength2, 0, 'foo length after removing an attribute when appended to document' );
  2232 	assert_equals( barLength2, 0, 'bar length after removing an attribute when appended to document' );
  2233 	assert_equals( bazLength2, 1, 'baz length after removing an attribute' );
  2234 	assert_equals( baz0, parEl.lastChild, 'baz[0] after removing an attribute' );
  2235 }, 'PropertyNodeList must update when changing duplicated id of referenced sibling');
  2236 test(function () {
  2237 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
  2238 	var testEl = parEl.childNodes[1];
  2239 	var PNL = testEl.properties.namedItem('foo');
  2240 	assert_equals( PNL.length, 0, 'length (before test)' );
  2241 	testEl.itemRef.toggle('id1');
  2242 	assert_equals( PNL.length, 1, 'length after itemref is changed' );
  2243 	assert_equals( PNL[0], parEl.firstChild, 'item 0 after itemref is changed' );
  2244 	testEl.removeAttribute('itemref');
  2245 	assert_equals( PNL.length, 0, 'length after itemref is removed' );
  2246 	assert_true( !PNL[0], 'item 0 after itemref is removed' );
  2247 	document.body.appendChild(parEl);
  2248 	var length0 = PNL.length;
  2249 	testEl.itemRef.toggle('id1');
  2250 	var length1 = PNL.length;
  2251 	var foo0 = PNL[0];
  2252 	testEl.removeAttribute('itemref');
  2253 	var length2 = PNL.length;
  2254 	var foo1 = PNL[0];
  2255 	document.body.removeChild(parEl);
  2256 	assert_equals( length0, 0, 'length (before test) when appended to document' );
  2257 	assert_equals( length1, 1, 'length after itemref is changed when appended to document' );
  2258 	assert_equals( foo0, parEl.firstChild, 'item 0 after itemref is changed when appended to document' );
  2259 	assert_equals( length2, 0, 'length after itemref is removed when appended to document' );
  2260 	assert_true( !foo1, 'item 0 after itemref is removed when appended to document' );
  2261 }, 'PropertyNodeList must update when changing itemref to point to an element');
  2262 test(function () {
  2263 	var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
  2264 	var testEl = parEl.childNodes[1];
  2265 	var PNLfoo = testEl.properties.namedItem('foo'), PNLbar = testEl.properties.namedItem('bar');
  2266 	assert_equals( PNLfoo.length, 0, 'foo length (before test)' );
  2267 	assert_equals( PNLbar.length, 0, 'bar length (before test)' );
  2268 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2269 	assert_equals( PNLfoo.length, 1, 'foo length after a referenced element is added' );
  2270 	assert_equals( PNLbar.length, 0, 'bar length after a referenced element is added' );
  2271 	assert_equals( PNLfoo.item(0), parEl.firstChild.lastChild, 'foo 0 after a referenced element is added' ); //uses item just for the fun of it
  2272 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  2273 	assert_equals( PNLfoo.length, 1, 'foo length after a referenced itemprop is changed' );
  2274 	assert_equals( PNLbar.length, 1, 'bar length after a referenced itemprop is changed' );
  2275 	assert_equals( PNLfoo[0], parEl.firstChild.lastChild, 'foo 0 after a referenced element is added' );
  2276 	assert_equals( PNLbar[0], parEl.firstChild.firstChild, 'bar 0 after a referenced element is added' );
  2277 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  2278 	assert_equals( PNLfoo.length, 1, 'foo length after a referenced element is removed' );
  2279 	assert_equals( PNLbar.length, 0, 'bar length after a referenced element is removed' );
  2280 	assert_equals( PNLfoo[0], parEl.firstChild.firstChild, 'foo 0 after a referenced element is removed' );
  2281 	assert_true( !PNLbar[0], 'bar 0 after a referenced element is removed' );
  2282 	parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
  2283 	testEl = parEl.childNodes[1];
  2284 	PNLfoo = testEl.properties.namedItem('foo');
  2285 	PNLbar = testEl.properties.namedItem('bar');
  2286 	document.body.appendChild(parEl);
  2287 	var step1fooLength = PNLfoo.length;
  2288 	var step1barLength = PNLbar.length;
  2289 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2290 	var step2fooLength = PNLfoo.length;
  2291 	var step2barLength = PNLbar.length;
  2292 	var step2foo0 = PNLfoo.item(0); //uses item just for the fun of it
  2293 	var step2fooExpected = parEl.firstChild.lastChild;
  2294 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  2295 	var step3fooLength = PNLfoo.length;
  2296 	var step3barLength = PNLbar.length;
  2297 	var step3foo0 = PNLfoo[0];
  2298 	var step3bar0 = PNLbar[0];
  2299 	var step3fooExpected = parEl.firstChild.lastChild;
  2300 	var step3barExpected = parEl.firstChild.firstChild;
  2301 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  2302 	var step4fooLength = PNLfoo.length;
  2303 	var step4barLength = PNLbar.length;
  2304 	var step4foo0 = PNLfoo[0];
  2305 	var step4bar0 = PNLbar[0];
  2306 	var step4fooExpected = parEl.firstChild.firstChild;
  2307 	document.body.removeChild(parEl);
  2308 	assert_equals( step1fooLength, 0, 'foo length (before test) when appended to document' );
  2309 	assert_equals( step1barLength, 0, 'bar length (before test) when appended to document' );
  2310 	assert_equals( step2fooLength, 1, 'foo length after a referenced element is added when appended to document' );
  2311 	assert_equals( step2barLength, 0, 'bar length after a referenced element is added when appended to document' );
  2312 	assert_equals( step2foo0, step2fooExpected, 'foo 0 after a referenced element is added when appended to document' );
  2313 	assert_equals( step3fooLength, 1, 'foo length after a referenced itemprop is changed when appended to document' );
  2314 	assert_equals( step3barLength, 1, 'bar length after a referenced itemprop is changed when appended to document' );
  2315 	assert_equals( step3foo0, step3fooExpected, 'foo 0 after a referenced element is added when appended to document' );
  2316 	assert_equals( step3bar0, step3barExpected, 'bar 0 after a referenced element is added when appended to document' );
  2317 	assert_equals( step4fooLength, 1, 'foo length after a referenced element is removed when appended to document' );
  2318 	assert_equals( step4barLength, 0, 'bar length after a referenced element is removed when appended to document' );
  2319 	assert_equals( step4foo0, step4fooExpected, 'foo 0 after a referenced element is removed when appended to document' );
  2320 	assert_true( !step4bar0, 'bar 0 after a referenced element is removed when appended to document' );
  2321 }, 'PropertyNodeList must update when changing children of elements referenced through itemref');
  2322 test(function () {
  2323 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="foo"></div></div>');
  2324 	var testEl = parEl.childNodes[1];
  2325 	var PNL = testEl.properties.namedItem('foo');
  2326 	assert_equals( PNL.length, 2, 'length (before test)' );
  2327 	assert_equals( PNL[0], parEl.firstChild, 'item 0 (before test)' );
  2328 	assert_equals( PNL[1], testEl.firstChild, 'item 1 (before test)' );
  2329 	document.body.appendChild(testEl);
  2330 	var step1length = PNL.length;
  2331 	var step1prop0 = PNL[0];
  2332 	var step1prop1 = PNL[1];
  2333 	parEl.appendChild(testEl);
  2334 	assert_equals( step1length, 1, 'length after changing parent' );
  2335 	assert_equals( step1prop0, testEl.firstChild, 'item 0 after changing parent' );
  2336 	assert_true( !step1prop1, 'item 1 after changing parent' );
  2337 	assert_equals( PNL.length, 2, 'length after re-parenting' );
  2338 	assert_equals( PNL[0], parEl.firstChild, 'item 0 after re-parenting' );
  2339 	assert_equals( PNL[1], testEl.firstChild, 'item 1 after re-parenting' );
  2340 	document.body.appendChild(parEl);
  2341 	var step2length = PNL.length;
  2342 	var step2prop0 = PNL[0];
  2343 	var step2prop1 = PNL[1];
  2344 	document.createElement('div').appendChild(testEl);
  2345 	var step3length = PNL.length;
  2346 	var step3prop0 = PNL[0];
  2347 	var step3prop1 = PNL[1];
  2348 	parEl.appendChild(testEl);
  2349 	var step4length = PNL.length;
  2350 	var step4prop0 = PNL[0];
  2351 	var step4prop1 = PNL[1];
  2352 	document.body.removeChild(parEl);
  2353 	assert_equals( step2length, 2, 'length (before test) when appended to document' );
  2354 	assert_equals( step2prop0, parEl.firstChild, 'item 0 (before test) when appended to document' );
  2355 	assert_equals( step2prop1, testEl.firstChild, 'item 1 (before test) when appended to document' );
  2356 	assert_equals( step3length, 1, 'length after changing parent when appended to document' );
  2357 	assert_equals( step3prop0, testEl.firstChild, 'item 0 after changing parent when appended to document' );
  2358 	assert_true( !step3prop1, 'item 1 after changing parent when appended to document' );
  2359 	assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
  2360 	assert_equals( step4prop0, parEl.firstChild, 'item 0 after re-parenting when appended to document' );
  2361 	assert_equals( step4prop1, testEl.firstChild, 'item 1 after re-parenting when appended to document' );
  2362 }, 'PropertyNodeList must update when appending elements with itemref to different parents');
  2363 test(function () {
  2364 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
  2365 	var PNL = testEl.properties.namedItem('foo');
  2366 	assert_equals( PNL.length, 1, 'length (before test)' );
  2367 	assert_equals( PNL[0], testEl.firstChild.firstChild, 'foo 0 (before test)' );
  2368 	testEl.firstChild.itemScope = true;
  2369 	assert_equals( PNL.length, 0, 'length after setting itemscope' );
  2370 	assert_true( !PNL[0], 'foo 0 after setting itemscope' );
  2371 	testEl.firstChild.removeAttribute('itemscope');
  2372 	assert_equals( PNL.length, 1, 'length after removing itemscope attribute' );
  2373 	assert_equals( PNL[0], testEl.firstChild.firstChild, 'foo 0 after removing itemscope attribute' );
  2374 }, 'PropertyNodeList must update when changing itemscope of children');
  2375 //PropertyNodeList.getValues
  2376 test(function () {
  2377 	var valuesArray = makeEl('div',{}).properties.namedItem('foo').getValues();
  2378 	assert_true( valuesArray instanceof Array, 'instanceof test' );
  2379 	Array.prototype.customProp = true;
  2380 	assert_true( valuesArray.customProp, 'inheritance test' );
  2381 }, 'getValues must return an array');
  2382 test(function () {
  2383 	var testEl = makeEl('div',{});
  2384 	var props = testEl.properties.namedItem('foo');
  2385 	assert_not_equals( props.getValues(), props.getValues() );
  2386 }, 'getValues must always return a newly constructed array');
  2387 test(function () {
  2388 	var parEl = makeEl('div',{},'<div id="id1"></div>');
  2389 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
  2390 	parEl.appendChild(testEl);
  2391 	testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
  2392 	testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2393 	testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
  2394 	testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2395 	testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
  2396 	testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
  2397 	testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
  2398 	testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2399 	testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
  2400 	testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
  2401 	testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
  2402 	testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
  2403 	parEl.appendChild(makeEl('time',{itemprop:'foo',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2404 	testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2405 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2406 	testEl.appendChild(makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2407 	var PNL = testEl.properties.namedItem('foo');
  2408 	var valuesArray = PNL.getValues();
  2409 	for( var i = 0; i < PNL.length; i++ ) {
  2410 		assert_equals( valuesArray[i], PNL[i].itemValue, 'property index ' + i + ', tag ' + PNL[i].tagName );
  2412 	assert_equals( valuesArray.length, 20, 'length' );
  2413 }, 'getValues array must contain the same item values as itemValue would return for the given properties');
  2414 test(function () {
  2415 	var parEl = makeEl('div',{},'<div id="id1"></div>');
  2416 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
  2417 	parEl.appendChild(testEl);
  2418 	testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
  2419 	testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2420 	testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
  2421 	testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2422 	testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
  2423 	testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
  2424 	testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
  2425 	testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2426 	testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
  2427 	testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
  2428 	testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
  2429 	testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
  2430 	parEl.appendChild(makeEl('time',{itemprop:'foo',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2431 	testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2432 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2433 	testEl.appendChild(makeEl('madeuponthespot',{itemprop:'foo'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2434 	var PNL = testEl.properties.namedItem('foo');
  2435 	var valuesArray = PNL.getValues();
  2436 	var staticArray = [];
  2437 	for( var i = 0; i < PNL.length; i++ ) {
  2438 		staticArray[i] = PNL[i].itemValue;
  2440 	testEl.innerHTML = '';
  2441 	parEl.firstChild.firstChild.childNodes[1].itemScope = false;
  2442 	assert_equals( valuesArray.length, staticArray.length, 'length after modification' );
  2443 	for( var j = 0; j < staticArray.length; j++ ) {
  2444 		assert_equals( valuesArray[j], staticArray[j], 'property index ' + j );
  2446 	assert_equals( valuesArray[1], parEl.firstChild.firstChild.childNodes[1], 'retaining pointer after modification' );
  2447 	staticArray = null;
  2448 	parEl.firstChild.firstChild.innerHTML = '';
  2449 	assert_equals( valuesArray[1] && valuesArray[1].nodeType, 1, 'retaining pointer after removal' );
  2450 }, 'getValues array must not be live');
  2451 //names
  2452 test(function () {
  2453 	assert_equals( typeof makeEl('div',{}).properties.names, 'object' );
  2454 }, 'the names property must be an object');
  2455 test(function () {
  2456 	var testEl = makeEl('div',{});
  2457 	assert_true( testEl.properties.names instanceof DOMStringList, 'instanceof DOMStringList' );
  2458 	DOMStringList.prototype.stringCustomProperty = true;
  2459 	assert_true( testEl.properties.names.stringCustomProperty, 'inheritance from DOMStringList' );
  2460 }, 'the names property must implement DOMStringList');
  2461 test(function () {
  2462 	var failed = false, elem = makeEl('div',{itemscope:'itemscope'}), realList = elem.properties.names;
  2463 	try {
  2464 		elem.properties.names = '';
  2465 	} catch(e) {
  2466 		failed = e;
  2468 	assert_equals(elem.properties.names,realList);
  2469 	assert_false(failed,'an error was thrown');
  2470 }, 'the names property must be read-only');
  2471 test(function () {
  2472 	var testEl = makeEl('div',{});
  2473 	assert_equals( testEl.properties.names, testEl.properties.names );
  2474 }, 'the names property must always reference the same object');
  2475 test(function () {
  2476 	var testEl = makeEl('div',{});
  2477 	assert_equals( testEl.properties.names.item(0), null, 'item(0)' );
  2478 	assert_equals( testEl.properties.names.item(-1), null, 'item(-1)' );
  2479 }, 'names.item() must return null for out of range indexes');
  2480 test(function () {
  2481 	var testEl = makeEl('div',{});
  2482 	assert_equals( testEl.properties.names[0], window.undefined, '[0]' );
  2483 	assert_equals( testEl.properties.names[-1], window.undefined, '[-1]' );
  2484 }, 'names[index] must return undefined for out of range indexes');
  2485 test(function () {
  2486 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  2487 	assert_equals( testEl.properties.names.length, 0, 'length' );
  2488 	assert_true( !testEl.properties.names.item(0), 'item(0)' );
  2489 	assert_true( !testEl.properties.names[0], '[0]' );
  2490 	assert_false( testEl.properties.names.contains('foo'), 'contains' );
  2491 }, 'the names collection must be empty if the element does not have an itemscope property');
  2492 test(function () {
  2493 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  2494 	testEl.itemScope = true;
  2495 	assert_equals( testEl.properties.names.length, 1, 'length' );
  2496 	assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
  2497 	assert_equals( testEl.properties.names[0], 'foo', '[0]' );
  2498 	assert_true( testEl.properties.names.contains('foo'), 'contains' );
  2499 }, 'the names collection must become populated if the element is given an itemscope property');
  2500 test(function () {
  2501 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
  2502 	testEl.itemScope = false;
  2503 	assert_equals( testEl.properties.names.length, 0, 'length' );
  2504 	assert_true( !testEl.properties.names.item(0), 'item(0)' );
  2505 	assert_true( !testEl.properties.names[0], '[0]' );
  2506 	assert_false( testEl.properties.names.contains('foo'), 'contains' );
  2507 }, 'the names collection must become empty if the element\'s itemscope property is removed');
  2508 test(function () {
  2509 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  2510 	testEl.properties.names.item = 'test';
  2511 	testEl.properties.names.contains = 'test';
  2512 	assert_equals( testEl.properties.names.item, 'test', 'item' );
  2513 	assert_equals( testEl.properties.names.contains, 'test', 'contains' );
  2514 }, 'the names.item and names.contains methods should be overwriteable');
  2515 test(function () {
  2516 	var testEl = makeEl('div',{},'<div itemprop="foo">bar</div>');
  2517 	testEl.properties.names.localCustomProperty = 'test';
  2518 	assert_equals( testEl.properties.names.localCustomProperty, 'test' );
  2519 }, 'the names.customProperty should be writeable');
  2520 test(function () {
  2521 	//WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter
  2522 	//ES5 makes [[Put]] fail but not throw
  2523 	var failed = false;
  2524 	var elem = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo">bar</div>');
  2525 	try {
  2526 		elem.properties.names.length = 0;
  2527 	} catch(e) {
  2528 		failed = e;
  2530 	assert_equals(elem.properties.names.length,1);
  2531 	assert_false(failed,'an error was thrown');
  2532 }, 'names.length must be read-only');
  2533 test(function () {
  2534 	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>');
  2535 	assert_equals( testEl.properties.names.length, 4 );
  2536 }, 'names.length must be the total number of property names');
  2537 test(function () {
  2538 	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>');
  2539 	assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
  2540 	assert_equals( testEl.properties.names.item(1), 'bar', 'item(1)' );
  2541 	assert_equals( testEl.properties.names.item(2), 'baz', 'item(2)' );
  2542 	assert_equals( testEl.properties.names.item(3), 'qux', 'item(3)' );
  2543 	assert_equals( testEl.properties.names[0], 'foo', '[0]' );
  2544 	assert_equals( testEl.properties.names[1], 'bar', '[1]' );
  2545 	assert_equals( testEl.properties.names[2], 'baz', '[2]' );
  2546 	assert_equals( testEl.properties.names[3], 'qux', '[3]' );
  2547 }, 'names.item must give each property name in tree order');
  2548 test(function () {
  2549 	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>');
  2550 	assert_equals( testEl.properties.names.length, 6, 'length' );
  2551 	assert_equals( testEl.properties.names.item(0), 'foo', 'item(0)' );
  2552 	assert_equals( testEl.properties.names.item(1), 'bar', 'item(1)' );
  2553 	assert_equals( testEl.properties.names.item(2), 'BAR', 'item(2)' );
  2554 	assert_equals( testEl.properties.names.item(3), 'FOO', 'item(3)' );
  2555 	assert_equals( testEl.properties.names.item(4), 'baz', 'item(4)' );
  2556 	assert_equals( testEl.properties.names.item(5), 'qux', 'item(5)' );
  2557 	assert_equals( testEl.properties.names[0], 'foo', '[0]' );
  2558 	assert_equals( testEl.properties.names[1], 'bar', '[1]' );
  2559 	assert_equals( testEl.properties.names[2], 'BAR', '[2]' );
  2560 	assert_equals( testEl.properties.names[3], 'FOO', '[3]' );
  2561 	assert_equals( testEl.properties.names[4], 'baz', '[4]' );
  2562 	assert_equals( testEl.properties.names[5], 'qux', '[5]' );
  2563 }, 'names must be case sensitive');
  2564 test(function () {
  2565 	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>');
  2566 	assert_true( testEl.properties.names.contains('foo'), 'foo' );
  2567 	assert_true( testEl.properties.names.contains('FOO'), 'FOO' );
  2568 	assert_true( testEl.properties.names.contains('bar'), 'bar' );
  2569 	assert_false( testEl.properties.names.contains('BAR'), 'BAR' );
  2570 	assert_true( testEl.properties.names.contains('baz'), 'baz' );
  2571 	assert_true( testEl.properties.names.contains('qux'), 'qux' );
  2572 	assert_false( testEl.properties.names.contains('madeup'), 'madeup' );
  2573 }, 'names.contains must return boolean if the name exists');
  2574 test(function () {
  2575 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="1"></div>');
  2576 	assert_equals( testEl.properties.names.item('1'), null );
  2577 }, 'names.item must cast to number');
  2578 test(function () {
  2579 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="1"></div>');
  2580 	assert_true( testEl.properties.names.contains({ valueOf: function () { return 2; }, toString: function () { return 'foo'; } }), 'object' );
  2581 	assert_true( testEl.properties.names.contains(1), 'number' );
  2582 }, 'names.contains must cast to string');
  2583 test(function () {
  2584 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
  2585 	var namesList = testEl.properties.names;
  2586 	testEl.innerHTML = '<div itemprop="baz"></div>';
  2587 	assert_equals( testEl.properties.names.length, 1, 'length' );
  2588 	assert_equals( testEl.properties.names[0], 'baz', '[0]' );
  2589 }, 'the names collection must be live');
  2590 test(function () {
  2591 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="|§!&quot;#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_&lt;&gt;帿ŨÆ"></div>');
  2592 	assert_equals( testEl.properties.names[0], '|§!"#¤%&/()=?`\\@£${[]}´€^¨~\'*,;.:-_<>帿ŨÆ' );
  2593 }, 'names must reflect property names containing special characters');
  2594 test(function () {
  2595 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemscope><div itemprop="bar"></div></div>');
  2596 	assert_equals( testEl.properties.names.length, 1, 'length' );
  2597 	assert_equals( testEl.properties.names[0], 'foo', '[0]' );
  2598 	assert_true( testEl.properties.names.contains('foo'), 'contains(foo)' );
  2599 	assert_false( testEl.properties.names.contains('bar'), 'contains(bar)' );
  2600 }, 'names must ignore properties of nested items');
  2601 test(function () {
  2602 	//note, itemref ordering is reversed compared with the next test to catch failed sorting algorithms
  2603 	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>');
  2604 	var testEl = parEl.childNodes[1];
  2605 	document.body.appendChild(parEl);
  2606 	var length = testEl.properties.names.length;
  2607 	var names0 = testEl.properties.names[0];
  2608 	var names1 = testEl.properties.names[1];
  2609 	var names2 = testEl.properties.names[2];
  2610 	var names3 = testEl.properties.names[3];
  2611 	document.body.removeChild(parEl);
  2612 	assert_equals( length, 4, 'length' );
  2613 	assert_equals( names0, 'foo', 'names[0]' );
  2614 	assert_equals( names1, 'bar', 'names[1]' );
  2615 	assert_equals( names2, 'baz', 'names[2]' );
  2616 	assert_equals( names3, 'qux', 'names[3]' );
  2617 }, 'names must see items added with itemref when attached to the document\'s DOM');
  2618 test(function () {
  2619 	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>');
  2620 	var testEl = parEl.childNodes[1];
  2621 	assert_equals( testEl.properties.names.length, 4, 'length' );
  2622 	assert_equals( testEl.properties.names[0], 'foo', 'names[0]' );
  2623 	assert_equals( testEl.properties.names[1], 'bar', 'names[1]' );
  2624 	assert_equals( testEl.properties.names[2], 'baz', 'names[2]' );
  2625 	assert_equals( testEl.properties.names[3], 'qux', 'names[3]' );
  2626 }, 'names must see items added with itemref');
  2627 test(function () {
  2628 	//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
  2629 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  2630 	var DSL = testEl.properties.names;
  2631 	testEl.removeAttribute('itemscope');
  2632 	assert_equals( testEl.properties.names.length, 0, 'removing attribute' );
  2633 	assert_equals( DSL.length, 0, 'removing attribute (live)' );
  2634 	assert_true( !testEl.properties.names[0], 'removing attribute [0]' );
  2635 	assert_true( !DSL[0], 'removing attribute [0] (live)' );
  2636 	testEl.itemScope = true;
  2637 	assert_equals( testEl.properties.names.length, 1, 'setting itemScope' );
  2638 	assert_equals( DSL.length, 1, 'setting itemScope (live)' );
  2639 	assert_equals( testEl.properties.names[0], 'foo', 'names[0] after setting itemScope' );
  2640 	assert_equals( DSL[0], 'foo', 'names[0] after setting itemScope (live)' );
  2641 }, 'names must update when adding itemscope on the root');
  2642 test(function () {
  2643 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div>');
  2644 	assert_equals( testEl.properties.names.length, 1, 'length (before test)' );
  2645 	assert_equals( testEl.properties.names[0], 'foo', 'item 0 (before test)' );
  2646 	testEl.appendChild(makeEl('div',{itemprop:'bar'}));
  2647 	assert_equals( testEl.properties.names.length, 2, 'length after adding a child' );
  2648 	assert_equals( testEl.properties.names[0], 'foo', 'item 0 after adding a child' );
  2649 	assert_equals( testEl.properties.names[1], 'bar', 'item 1 after adding a child' );
  2650 	testEl.lastChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2651 	assert_equals( testEl.properties.names.length, 2, 'foo length after adding a child with duplicated name' );
  2652 	assert_equals( testEl.properties.names[0], 'foo', 'item 0 after adding a child with duplicated name' );
  2653 	assert_equals( testEl.properties.names[1], 'bar', 'item 1 after adding a child with duplicated name' );
  2654 	testEl.removeChild(testEl.lastChild);
  2655 	assert_equals( testEl.properties.names.length, 1, 'length after removing a child' );
  2656 	assert_equals( testEl.properties.names[0], 'foo', 'item 0 after removing a child' );
  2657 }, 'names must update when adding property elements');
  2658 test(function () {
  2659 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div>');
  2660 	var DSL = testEl.properties.names;
  2661 	assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
  2662 	assert_equals( DSL[1], 'bar', 'item 1 (before test)' );
  2663 	testEl.appendChild(testEl.firstChild);
  2664 	assert_equals( DSL[0], 'bar', 'item 0 (after test)' );
  2665 	assert_equals( DSL[1], 'foo', 'item 1 (after test)' );
  2666 }, 'names must update when re-ordering property elements');
  2667 test(function () {
  2668 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div></div>');
  2669 	var DSL = testEl.properties.names;
  2670 	assert_equals( DSL.length, 1, 'length (before test)' );
  2671 	assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
  2672 	testEl.lastChild.itemProp.toggle('bar');
  2673 	assert_equals( DSL.length, 2, 'length after adding a token' );
  2674 	assert_equals( DSL[0], 'foo', 'item 0 after adding a token' );
  2675 	assert_equals( DSL[1], 'bar', 'item 1 after adding a token' );
  2676 	testEl.lastChild.itemProp.add('foo');
  2677 	assert_equals( DSL.length, 2, 'length after adding a duplicated token' );
  2678 	assert_equals( DSL[0], 'foo', 'item 0 after adding a duplicated token' );
  2679 	assert_equals( DSL[1], 'bar', 'item 1 after adding a duplicated token' );
  2680 	testEl.lastChild.removeAttribute('itemprop');
  2681 	assert_equals( DSL.length, 1, 'length after removing an attribute' );
  2682 	assert_equals( DSL[0], 'foo', 'item 0 after removing an attribute' );
  2683 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo"></div><div itemprop="bar"></div><div itemprop="foo"></div>');
  2684 	DSL = testEl.properties.names;
  2685 	assert_equals( DSL.length, 2, 'length (before second test)' );
  2686 	assert_equals( DSL[0], 'foo', 'item 0 (before second test)' );
  2687 	assert_equals( DSL[1], 'bar', 'item 1 (before second test)' );
  2688 	testEl.firstChild.removeAttribute('itemprop');
  2689 	assert_equals( DSL.length, 2, 'length after removing attribute of first item' );
  2690 	assert_equals( DSL[0], 'bar', 'item 0 after removing attribute of first item' );
  2691 	assert_equals( DSL[1], 'foo', 'item 1 after removing attribute of first item' );
  2692 	testEl.firstChild.itemProp.add('foo');
  2693 	assert_equals( DSL.length, 2, 'length after adding duplicated token to first item' );
  2694 	assert_equals( DSL[0], 'foo', 'item 0 after adding duplicated token to first item' );
  2695 	assert_equals( DSL[1], 'bar', 'item 1 after adding duplicated token to first item' );
  2696 	testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="foo bar"></div>');
  2697 	DSL = testEl.properties.names;
  2698 	assert_equals( DSL.length, 2, 'length (before third test)' );
  2699 	assert_equals( DSL[0], 'foo', 'item 0 (before third test)' );
  2700 	assert_equals( DSL[1], 'bar', 'item 1 (before third test)' );
  2701 	testEl.firstChild.itemProp.toggle('foo');
  2702 	testEl.firstChild.itemProp.toggle('foo');
  2703 	assert_equals( DSL.length, 2, 'length after swapping tokens' );
  2704 	assert_equals( DSL[0], 'bar', 'item 0 after swapping tokens' );
  2705 	assert_equals( DSL[1], 'foo', 'item 1 after swapping tokens' );
  2706 }, 'names must update when changing itemProp of children');
  2707 test(function () {
  2708 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div>');
  2709 	var testEl = parEl.childNodes[1];
  2710 	var DSL = testEl.properties.names;
  2711 	assert_equals( DSL.length, 0, 'length (before test)' );
  2712 	parEl.firstChild.id = 'id1';
  2713 	assert_equals( DSL.length, 2, 'length after id is created' );
  2714 	assert_equals( DSL[0], 'foo', 'item 0 after id is created' );
  2715 	assert_equals( DSL[1], 'bar', 'item 1 after id is created' );
  2716 	parEl.firstChild.removeAttribute('id');
  2717 	assert_equals( DSL.length, 0, 'length after removing an attribute' );
  2718 	document.body.appendChild(parEl);
  2719 	var step1length = DSL.length;
  2720 	parEl.firstChild.id = 'id1';
  2721 	var step2length = DSL.length;
  2722 	var step2item0 = DSL[0];
  2723 	var step2item1 = DSL[1];
  2724 	parEl.firstChild.removeAttribute('id');
  2725 	var step3length = DSL.length;
  2726 	document.body.removeChild(parEl);
  2727 	assert_equals( step1length, 0, 'length (before test) when appended to document' );
  2728 	assert_equals( step2length, 2, 'length after id is created when appended to document' );
  2729 	assert_equals( step2item0, 'foo', 'item 0 after id is created when appended to document' );
  2730 	assert_equals( step2item1, 'bar', 'item 1 after id is created when appended to document' );
  2731 	assert_equals( step3length, 0, 'length after removing an attribute when appended to document' );
  2732 }, 'names must update when changing id of referenced sibling when appended to document');
  2733 test(function () {
  2734 	var parEl = makeEl('div',{},'<div itemprop="foo"><div itemprop="bar"></div></div><div itemscope itemref="id1"></div><div itemprop="baz" id="id1"></div>');
  2735 	var testEl = parEl.childNodes[1];
  2736 	var DSL = testEl.properties.names;
  2737 	assert_equals( DSL.length, 1, 'length (before test)' );
  2738 	assert_equals( DSL[0], 'baz', 'item 0 (before test)' );
  2739 	parEl.firstChild.id = 'id1';
  2740 	assert_equals( DSL.length, 2, 'length after id is created' );
  2741 	assert_equals( DSL[0], 'foo', 'item 0 after id is created' );
  2742 	assert_equals( DSL[1], 'bar', 'item 1 after id is created' );
  2743 	parEl.firstChild.removeAttribute('id');
  2744 	assert_equals( DSL.length, 1, 'length after removing an attribute' );
  2745 	assert_equals( DSL[0], 'baz', 'item 0 after removing an attribute' );
  2746 	document.body.appendChild(parEl);
  2747 	var step1length = DSL.length;
  2748 	var step1item0 = DSL[0];
  2749 	parEl.firstChild.id = 'id1';
  2750 	var step2length = DSL.length;
  2751 	var step2item0 = DSL[0];
  2752 	var step2item1 = DSL[1];
  2753 	parEl.firstChild.removeAttribute('id');
  2754 	var step3length = DSL.length;
  2755 	var step3item0 = DSL[0];
  2756 	document.body.removeChild(parEl);
  2757 	assert_equals( step1length, 1, 'length (before test)' );
  2758 	assert_equals( step1item0, 'baz', 'item 0 (before test)' );
  2759 	assert_equals( step2length, 2, 'length after id is created' );
  2760 	assert_equals( step2item0, 'foo', 'item 0 after id is created' );
  2761 	assert_equals( step2item1, 'bar', 'item 1 after id is created' );
  2762 	assert_equals( step3length, 1, 'length after removing an attribute' );
  2763 	assert_equals( step3item0, 'baz', 'item 0 after removing an attribute' );
  2764 }, 'names must update when changing duplicated id of referenced sibling');
  2765 test(function () {
  2766 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope></div>');
  2767 	var testEl = parEl.childNodes[1];
  2768 	var DSL = testEl.properties.names;
  2769 	assert_equals( DSL.length, 0, 'length (before test)' );
  2770 	testEl.itemRef.toggle('id1');
  2771 	assert_equals( DSL.length, 1, 'length after itemref is changed' );
  2772 	assert_equals( DSL[0], 'foo', 'item 0 after itemref is changed' );
  2773 	testEl.removeAttribute('itemref');
  2774 	assert_equals( DSL.length, 0, 'length after itemref is removed' );
  2775 	assert_true( !DSL[0], 'item 0 after itemref is removed' );
  2776 	document.body.appendChild(parEl);
  2777 	var step1length = DSL.length;
  2778 	testEl.itemRef.toggle('id1');
  2779 	var step2length = DSL.length;
  2780 	var step2item = DSL[0];
  2781 	testEl.removeAttribute('itemref');
  2782 	var step3length = DSL.length;
  2783 	var step3item = DSL[0];
  2784 	document.body.removeChild(parEl);
  2785 	assert_equals( step1length, 0, 'length (before test)' );
  2786 	assert_equals( step2length, 1, 'length after itemref is changed' );
  2787 	assert_equals( step2item, 'foo', 'item 0 after itemref is changed' );
  2788 	assert_equals( step3length, 0, 'length after itemref is removed' );
  2789 	assert_true( !step3item, 'item 0 after itemref is removed' );
  2790 }, 'names must update when changing itemref to point to an element');
  2791 test(function () {
  2792 	var parEl = makeEl('div',{},'<div id="id1"><div></div></div><div itemscope itemref="id1"></div>');
  2793 	var testEl = parEl.childNodes[1];
  2794 	var DSL = testEl.properties.names;
  2795 	assert_equals( DSL.length, 0, 'length (before test)' );
  2796 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2797 	assert_equals( DSL.length, 1, 'length after a referenced element is added' );
  2798 	assert_equals( DSL.item(0), 'foo', 'item 0 after a referenced element is added' ); //uses item just for the fun of it
  2799 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  2800 	assert_equals( DSL.length, 2, 'length after a referenced itemprop is changed' );
  2801 	assert_equals( DSL[0], 'bar', 'item 0 after a referenced element is added' );
  2802 	assert_equals( DSL[1], 'foo', 'item 1 after a referenced element is added' );
  2803 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  2804 	assert_equals( DSL.length, 1, 'length after a referenced element is removed' );
  2805 	assert_equals( DSL[0], 'foo', 'item 0 after a referenced element is removed' );
  2806 	parEl.innerHTML = '<div id="id1"><div></div></div><div itemscope itemref="id1"></div>';
  2807 	testEl = parEl.childNodes[1];
  2808 	DSL = testEl.properties.names;
  2809 	document.body.appendChild(parEl);
  2810 	var step1length = DSL.length;
  2811 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2812 	var step2length = DSL.length;
  2813 	var step2item0 = DSL.item(0); //uses item just for the fun of it
  2814 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  2815 	var step3length = DSL.length;
  2816 	var step3item0 = DSL[0];
  2817 	var step3item1 = DSL[1];
  2818 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  2819 	var step4length = DSL.length;
  2820 	var step4item0 = DSL[0];
  2821 	document.body.removeChild(parEl);
  2822 	assert_equals( step1length, 0, 'length (before test)' );
  2823 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'foo'}));
  2824 	assert_equals( step2length, 1, 'length after a referenced element is added' );
  2825 	assert_equals( step2item0, 'foo', 'item 0 after a referenced element is added' ); //uses item just for the fun of it
  2826 	parEl.firstChild.firstChild.itemProp.toggle('bar');
  2827 	assert_equals( step3length, 2, 'length after a referenced itemprop is changed' );
  2828 	assert_equals( step3item0, 'bar', 'item 0 after a referenced element is added' );
  2829 	assert_equals( step3item1, 'foo', 'item 1 after a referenced element is added' );
  2830 	parEl.firstChild.removeChild(parEl.firstChild.firstChild);
  2831 	assert_equals( step4length, 1, 'length after a referenced element is removed' );
  2832 	assert_equals( step4item0, 'foo', 'item 0 after a referenced element is removed' );
  2833 }, 'names must update when changing children of elements referenced through itemref');
  2834 test(function () {
  2835 	var parEl = makeEl('div',{},'<div id="id1" itemprop="foo"></div><div itemscope itemref="id1"><div itemprop="bar"></div></div>');
  2836 	var testEl = parEl.childNodes[1];
  2837 	var DSL = testEl.properties.names;
  2838 	assert_equals( DSL.length, 2, 'length (before test)' );
  2839 	assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
  2840 	assert_equals( DSL[1], 'bar', 'item 1 (before test)' );
  2841 	document.body.appendChild(testEl);
  2842 	var step1length = DSL.length;
  2843 	var step1prop0 = DSL[0];
  2844 	var step1prop1 = DSL[1];
  2845 	parEl.appendChild(testEl);
  2846 	assert_equals( step1length, 1, 'length after changing parent' );
  2847 	assert_equals( step1prop0, 'bar', 'item 0 after changing parent' );
  2848 	assert_true( !step1prop1, 'item 1 after changing parent' );
  2849 	assert_equals( DSL.length, 2, 'length after re-parenting' );
  2850 	assert_equals( DSL[0], 'foo', 'item 0 after re-parenting' );
  2851 	assert_equals( DSL[1], 'bar', 'item 1 after re-parenting' );
  2852 	document.body.appendChild(parEl);
  2853 	var step2length = DSL.length;
  2854 	var step2prop0 = DSL[0];
  2855 	var step2prop1 = DSL[1];
  2856 	document.createElement('div').appendChild(testEl);
  2857 	var step3length = DSL.length;
  2858 	var step3prop0 = DSL[0];
  2859 	var step3prop1 = DSL[1];
  2860 	parEl.appendChild(testEl);
  2861 	var step4length = DSL.length;
  2862 	var step4prop0 = DSL[0];
  2863 	var step4prop1 = DSL[1];
  2864 	document.body.removeChild(parEl);
  2865 	assert_equals( step2length, 2, 'length (before test) when appended to document' );
  2866 	assert_equals( step2prop0, 'foo', 'item 0 (before test) when appended to document' );
  2867 	assert_equals( step2prop1, 'bar', 'item 1 (before test) when appended to document' );
  2868 	assert_equals( step3length, 1, 'length after changing parent when appended to document' );
  2869 	assert_equals( step3prop0, 'bar', 'item 0 after changing parent when appended to document' );
  2870 	assert_true( !step3prop1, 'item 1 after changing parent when appended to document' );
  2871 	assert_equals( step4length, 2, 'length after re-parenting when appended to document' );
  2872 	assert_equals( step4prop0, 'foo', 'item 0 after re-parenting when appended to document' );
  2873 	assert_equals( step4prop1, 'bar', 'item 1 after re-parenting when appended to document' );
  2874 }, 'names must update when appending elements with itemref to different parents');
  2875 test(function () {
  2876 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div><div itemprop="foo"></div></div>');
  2877 	var DSL = testEl.properties.names;
  2878 	assert_equals( DSL.length, 1, 'length (before test)' );
  2879 	assert_equals( DSL[0], 'foo', 'item 0 (before test)' );
  2880 	testEl.firstChild.itemScope = true;
  2881 	assert_equals( DSL.length, 0, 'length after setting itemscope' );
  2882 	assert_true( !DSL[0], 'item 0 after setting itemscope' );
  2883 	testEl.firstChild.removeAttribute('itemscope');
  2884 	assert_equals( DSL.length, 1, 'length after removing itemscope attribute' );
  2885 	assert_equals( DSL[0], 'foo', 'item 0 after removing itemscope attribute' );
  2886 }, 'names must update when changing itemscope of children');
  2888 /* potential bugs */
  2889 test(function () {
  2890 	var parEl = makeEl('div',{},'<div id="id1"></div>');
  2891 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1 id2'});
  2892 	parEl.appendChild(testEl);
  2893 	testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
  2894 	testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2895 	testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
  2896 	testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2897 	testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
  2898 	testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
  2899 	testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
  2900 	testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2901 	testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
  2902 	testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
  2903 	testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
  2904 	testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
  2905 	parEl.appendChild(makeEl('time',{itemprop:'bar',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2906 	testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2907 	parEl.firstChild.appendChild(makeEl('div',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2908 	testEl.appendChild(makeEl('madeuponthespot',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2909 	var properties, PNLfoo, PNLbar, PNLbaz, fooValues, barValues, bazValues, allArrays, snapshot = [];
  2910 	document.body.appendChild(parEl);
  2911 	try {
  2912 		properties = testEl.properties;
  2913 		PNLfoo = properties.namedItem('foo');
  2914 		PNLbar = properties.namedItem('bar');
  2915 		PNLbaz = properties.namedItem('baz');
  2916 		fooValues = PNLfoo.getValues();
  2917 		barValues = PNLbar.getValues();
  2918 		bazValues = PNLbaz.getValues();
  2919 		allArrays = [properties,PNLfoo,PNLbar,PNLbaz,fooValues,barValues,bazValues];
  2920 		for( var a = 0; a < allArrays.length; a++ ) {
  2921 			snapshot[a] = [];
  2922 			for( var b = 0; b < allArrays[a].length; b++ ) {
  2923 				snapshot[a][b] = allArrays[a][b];
  2926 	} catch(e) { /* need to clean up */ }
  2927 	document.body.removeChild(parEl);
  2928 	var c, d;
  2929 	for( c = 0; c < allArrays.length; c++ ) {
  2930 		for( d = 0; d < allArrays[c].length; d++ ) {
  2931 			assert_equals( snapshot[c][d], allArrays[c][d], 'allArrays['+c+']['+d+']' );
  2934 	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()];
  2935 	for( c = 0; c < newArrays.length; c++ ) {
  2936 		for( d = 0; d < newArrays[c].length; d++ ) {
  2937 			assert_equals( snapshot[c][d], newArrays[c][d], 'newArrays['+c+']['+d+']' );
  2940 }, 'collections must survive the parent\'s removal from the document');
  2941 test(function () {
  2942 	var testEl = makeEl('div',{itemscope:'itemscope'});
  2943 	testEl.appendChild(makeEl('meta',{itemprop:'foo',content:'test'}));
  2944 	testEl.appendChild(makeEl('audio',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2945 	testEl.appendChild(makeEl('embed',{itemprop:'foo',src:'http://example.org/'}));
  2946 	testEl.appendChild(makeEl('iframe',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2947 	testEl.appendChild(makeEl('img',{itemprop:'foo',src:'http://example.org/'}));
  2948 	testEl.appendChild(makeEl('source',{itemprop:'foo',src:'http://example.org/'}));
  2949 	testEl.appendChild(makeEl('track',{itemprop:'foo',src:'http://example.org/'}));
  2950 	testEl.appendChild(makeEl('video',{itemprop:'foo',src:'http://example.org/'},'contained text'));
  2951 	testEl.appendChild(makeEl('a',{itemprop:'foo',href:'http://example.org/'},'contained text'));
  2952 	testEl.appendChild(makeEl('area',{itemprop:'foo',href:'http://example.org/'}));
  2953 	testEl.appendChild(makeEl('link',{itemprop:'foo',href:'http://example.org/'}));
  2954 	testEl.appendChild(makeEl('object',{itemprop:'foo',data:'http://example.org/'},'contained text'));
  2955 	testEl.appendChild(makeEl('time',{itemprop:'bar',id:'id2'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2956 	testEl.appendChild(makeEl('time',{itemprop:'foo',datetime:'test'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2957 	testEl.appendChild(makeEl('div',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2958 	testEl.appendChild(makeEl('madeuponthespot',{itemprop:'baz'},'te <span itemprop="foo" itemscope>st</span> ing'));
  2959 	var properties, PNLfoo, PNLbar, PNLbaz, fooValues, barValues, bazValues, allArrays, snapshot = [];
  2960 	document.body.appendChild(testEl);
  2961 	try {
  2962 		properties = testEl.properties;
  2963 		PNLfoo = properties.namedItem('foo');
  2964 		PNLbar = properties.namedItem('bar');
  2965 		PNLbaz = properties.namedItem('baz');
  2966 		fooValues = PNLfoo.getValues();
  2967 		barValues = PNLbar.getValues();
  2968 		bazValues = PNLbaz.getValues();
  2969 		allArrays = [properties,PNLfoo,PNLbar,PNLbaz,fooValues,barValues,bazValues];
  2970 		for( var a = 0; a < allArrays.length; a++ ) {
  2971 			snapshot[a] = [];
  2972 			for( var b = 0; b < allArrays[a].length; b++ ) {
  2973 				snapshot[a][b] = allArrays[a][b];
  2976 	} catch(e) { /* need to clean up */ }
  2977 	document.body.removeChild(testEl);
  2978 	var c, d;
  2979 	for( c = 0; c < allArrays.length; c++ ) {
  2980 		for( d = 0; d < allArrays[c].length; d++ ) {
  2981 			assert_equals( snapshot[c][d], allArrays[c][d], 'allArrays['+c+']['+d+']' );
  2984 	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()];
  2985 	for( c = 0; c < newArrays.length; c++ ) {
  2986 		for( d = 0; d < newArrays[c].length; d++ ) {
  2987 			assert_equals( snapshot[c][d], newArrays[c][d], 'newArrays['+c+']['+d+']' );
  2990 }, 'collections must survive the item\'s removal from the document');
  2992 /* override_builtins */
  2993 test(function () {
  2994 	//http://dev.w3.org/2006/webapi/WebIDL/#named-properties
  2995 	//[OverrideBuiltins] is not declared for any of the properties, hence no overriding is allowed
  2996 	var testEl = makeEl('div',{itemscope:'itemscope'});
  2997 	var namedItem = testEl.properties.namedItem;
  2998 	var item = testEl.properties.item;
  2999 	var names = testEl.properties.names;
  3000 	testEl.innerHTML = '<div itemprop="namedItem length item names"></div>';
  3001 	assert_equals( testEl.properties['namedItem'], namedItem, 'namedItem' );
  3002 	assert_equals( testEl.properties['length'], 1, 'length' );
  3003 	assert_equals( testEl.properties['item'], item, 'item' );
  3004 	assert_equals( testEl.properties['names'], names, 'names' );
  3005 }, 'itemprop names must not override builtin properties');
  3007 /* casting */
  3008 //when calling object[other_object], ECMAScript treats other_object as a named property so it casts it to a string using toString
  3009 //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
  3010 test(function () {
  3011 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2"></div><div itemprop="0"></div>');
  3012 	assert_equals( testEl.properties.item('0'), testEl.properties.item(0), '0' );
  3013 	assert_equals( testEl.properties.item('2'), testEl.properties.item(2), '2' );
  3014 }, 'properties.item(integerString) should cast to a number');
  3015 test(function () {
  3016 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2"></div><div itemprop="0"></div>');
  3017 	assert_equals( testEl.properties['0'], testEl.properties.item(0), '0' );
  3018 	assert_equals( testEl.properties['2'], window.undefined, '2' );
  3019 }, 'properties[integerString] should act as a numeric index');
  3020 test(function () {
  3021 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="0"></div>');
  3022 	assert_equals( testEl.properties.namedItem(0), testEl.properties.namedItem('0'), '0' );
  3023 	assert_true( testEl.properties.namedItem(0) instanceof PropertyNodeList , 'instanceof' );
  3024 }, 'properties.namedItem(integer) should cast to a string');
  3025 test(function () {
  3026 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemprop="2 foo"></div><div itemprop="0"></div>');
  3027 	assert_equals( testEl.properties[{ toString: function(){return 'foo';}, valueOf: function(){return 1;} }][0], testEl.firstChild, 'foo' );
  3028 	assert_equals( testEl.properties[{ toString: function(){return '0';}, valueOf: function(){return 1;} }], testEl.firstChild, '0' );
  3029 	assert_equals( testEl.properties[{ toString: function(){return '2';}, valueOf: function(){return 0;} }], window.undefined, '2' );
  3030 }, 'properties[someObject] should cast toString before using whichever casting applies');
  3032 /* loops and evil itemref */
  3033 test(function () {
  3034 	//This should have 1 property on each itemscope, pointing only to its direct child
  3035 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo"><div itemprop="bar"></div></div>');
  3036 	assert_equals( testEl.properties.length, 1, 'outer length' );
  3037 	assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
  3038 	assert_true( !testEl.properties[1], 'outer properties[1]' );
  3039 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
  3040 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
  3041 	assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
  3042 	assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
  3043 	assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
  3044 	assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
  3045 	assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
  3046 	assert_true( !testEl.properties.names[1], 'outer names[1]' );
  3047 	assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
  3048 	assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
  3049 	assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
  3050 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
  3051 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
  3052 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
  3053 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
  3054 	assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1]' );
  3055 	assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
  3056 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
  3057 	assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
  3058 }, 'simple nested itemscope');
  3059 test(function () {
  3060 	//This should have 1 property on each itemscope, pointing only to its direct child
  3061 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'},'<div itemscope itemprop="foo" id="id1" itemref="id2"><div itemprop="bar" id="id2"></div></div>');
  3062 	assert_equals( testEl.properties.length, 1, 'outer length' );
  3063 	assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
  3064 	assert_true( !testEl.properties[1], 'outer properties[1]' );
  3065 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
  3066 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
  3067 	assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
  3068 	assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
  3069 	assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
  3070 	assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
  3071 	assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
  3072 	assert_true( !testEl.properties.names[1], 'outer names[1]' );
  3073 	assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
  3074 	assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
  3075 	assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
  3076 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
  3077 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
  3078 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
  3079 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
  3080 	assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1]' );
  3081 	assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
  3082 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
  3083 	assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
  3084 	document.body.appendChild(testEl);
  3085 	try {
  3086 		assert_equals( testEl.properties.length, 1, 'outer length when appended to document' );
  3087 		assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
  3088 		assert_true( !testEl.properties[1], 'outer properties[1] when appended to document' );
  3089 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
  3090 		assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
  3091 		assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
  3092 		assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length when appended to document' );
  3093 		assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0] when appended to document' );
  3094 		assert_equals( testEl.properties.names.length, 1, 'outer names.length when appended to document' );
  3095 		assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
  3096 		assert_true( !testEl.properties.names[1], 'outer names[1] when appended to document' );
  3097 		assert_equals( testEl.firstChild.properties.length, 1, 'inner length when appended to document' );
  3098 		assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
  3099 		assert_true( !testEl.firstChild.properties[1], 'inner properties[1] when appended to document' );
  3100 		assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
  3101 		assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
  3102 		assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
  3103 		assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
  3104 		assert_true( !testEl.firstChild.properties.namedItem('foo')[1], 'inner foo[1] when appended to document' );
  3105 		assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length when appended to document' );
  3106 		assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
  3107 		assert_true( !testEl.firstChild.properties.names[1], 'inner names[1] when appended to document' );
  3108 	} catch(e) {
  3109 		document.body.removeChild(testEl);
  3110 		throw (e);
  3112 	document.body.removeChild(testEl);
  3113 }, 'simple nested itemscope with itemref');
  3114 test(function () {
  3115 	//This should have 3 properties on the item; foo, bar and baz
  3116 	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>');
  3117 	var testEl = parEl.childNodes[1];
  3118 	assert_equals( testEl.properties.length, 3, 'length' );
  3119 	assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0]' );
  3120 	assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1]' );
  3121 	assert_equals( testEl.properties[2], parEl.lastChild, 'properties[2]' );
  3122 	assert_true( !testEl.properties[3], 'properties[3]' );
  3123 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo.length' );
  3124 	assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo[0]' );
  3125 	assert_true( !testEl.properties.namedItem('foo')[1], 'foo[1]' );
  3126 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length' );
  3127 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
  3128 	assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1]' );
  3129 	assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz.length' );
  3130 	assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz[0]' );
  3131 	assert_true( !testEl.properties.namedItem('baz')[1], 'baz[1]' );
  3132 	assert_equals( testEl.properties.names.length, 3, 'names.length' );
  3133 	assert_equals( testEl.properties.names[0], 'foo', 'names[0]' );
  3134 	assert_equals( testEl.properties.names[1], 'bar', 'names[1]' );
  3135 	assert_equals( testEl.properties.names[2], 'baz', 'names[2]' );
  3136 	assert_true( !testEl.properties.names[3], 'names[3]' );
  3137 	document.body.appendChild(parEl);
  3138 	try {
  3139 		assert_equals( testEl.properties.length, 3, 'length when appended to document' );
  3140 		assert_equals( testEl.properties[0], parEl.firstChild, 'properties[0] when appended to document' );
  3141 		assert_equals( testEl.properties[1], testEl.firstChild, 'properties[1] when appended to document' );
  3142 		assert_equals( testEl.properties[2], parEl.lastChild, 'properties[2] when appended to document' );
  3143 		assert_true( !testEl.properties[3], 'properties[3] when appended to document' );
  3144 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'foo.length when appended to document' );
  3145 		assert_equals( testEl.properties.namedItem('foo')[0], parEl.firstChild, 'foo[0] when appended to document' );
  3146 		assert_true( !testEl.properties.namedItem('foo')[1], 'foo[1] when appended to document' );
  3147 		assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
  3148 		assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
  3149 		assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
  3150 		assert_equals( testEl.properties.namedItem('baz').length, 1, 'baz.length when appended to document' );
  3151 		assert_equals( testEl.properties.namedItem('baz')[0], parEl.lastChild, 'baz[0] when appended to document' );
  3152 		assert_true( !testEl.properties.namedItem('baz')[1], 'baz[1] when appended to document' );
  3153 		assert_equals( testEl.properties.names.length, 3, 'names.length when appended to document' );
  3154 		assert_equals( testEl.properties.names[0], 'foo', 'names[0] when appended to document' );
  3155 		assert_equals( testEl.properties.names[1], 'bar', 'names[1] when appended to document' );
  3156 		assert_equals( testEl.properties.names[2], 'baz', 'names[2] when appended to document' );
  3157 		assert_true( !testEl.properties.names[3], 'names[3] when appended to document' );
  3158 	} catch(e) {
  3159 		document.body.removeChild(parEl);
  3160 		throw (e);
  3162 	document.body.removeChild(parEl);
  3163 }, 'simple sibling itemref');
  3164 test(function () {
  3165 	//This should have no properties
  3166 	var testEl = makeEl('div',{itemscope:'itemscope',id:'id1',itemref:'id1',itemprop:'foo'});
  3167 	assert_equals( testEl.properties.length, 0, 'length' );
  3168 	assert_true( !testEl.properties[0], 'properties[0]' );
  3169 	assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length' );
  3170 	assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0]' );
  3171 	assert_equals( testEl.properties.names.length, 0, 'names.length' );
  3172 	assert_true( !testEl.properties.names[0], 'names[0]' );
  3173 	document.body.appendChild(testEl);
  3174 	try {
  3175 		assert_equals( testEl.properties.length, 0, 'length when appended to document' );
  3176 		assert_true( !testEl.properties[0], 'properties[0] when appended to document' );
  3177 		assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
  3178 		assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
  3179 		assert_equals( testEl.properties.names.length, 0, 'names.length when appended to document' );
  3180 		assert_true( !testEl.properties.names[0], 'names[0] when appended to document' );
  3181 	} catch(e) {
  3182 		document.body.removeChild(testEl);
  3183 		throw (e);
  3185 	document.body.removeChild(testEl);
  3186 }, 'itemref pointing to itself');
  3187 test(function () {
  3188 	//This should have 1 property, pointing to the child
  3189 	var testEl = makeEl('div',{itemscope:'itemscope',id:'id1',itemref:'id1',itemprop:'foo'},'<div itemprop="bar"></div>');
  3190 	assert_equals( testEl.properties.length, 1, 'length' );
  3191 	assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0]' );
  3192 	assert_true( !testEl.properties[1], 'properties[1]' );
  3193 	assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length' );
  3194 	assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0]' );
  3195 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length' );
  3196 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
  3197 	assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1]' );
  3198 	assert_equals( testEl.properties.names.length, 1, 'names.length' );
  3199 	assert_equals( testEl.properties.names[0], 'bar', 'names[0]' );
  3200 	assert_true( !testEl.properties.names[1], 'names[1]' );
  3201 	document.body.appendChild(testEl);
  3202 	try {
  3203 		assert_equals( testEl.properties.length, 1, 'length when appended to document' );
  3204 		assert_equals( testEl.properties[0], testEl.firstChild, 'properties[0] when appended to document' );
  3205 		assert_true( !testEl.properties[1], 'properties[1] when appended to document' );
  3206 		assert_equals( testEl.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
  3207 		assert_true( !testEl.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
  3208 		assert_equals( testEl.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
  3209 		assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
  3210 		assert_true( !testEl.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
  3211 		assert_equals( testEl.properties.names.length, 1, 'names.length when appended to document' );
  3212 		assert_equals( testEl.properties.names[0], 'bar', 'names[0] when appended to document' );
  3213 		assert_true( !testEl.properties.names[1], 'names[1] when appended to document' );
  3214 	} catch(e) {
  3215 		document.body.removeChild(testEl);
  3216 		throw (e);
  3218 	document.body.removeChild(testEl);
  3219 }, 'itemref pointing to itself with child');
  3220 test(function () {
  3221 	//This should have 1 property on each itemscope, pointing only to its direct child
  3222 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div itemscope itemprop="foo" id="id1" itemref="id1"><div itemprop="bar"></div></div>');
  3223 	assert_equals( testEl.properties.length, 1, 'outer length' );
  3224 	assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
  3225 	assert_true( !testEl.properties[1], 'outer properties[1]' );
  3226 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
  3227 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
  3228 	assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
  3229 	assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length' );
  3230 	assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0]' );
  3231 	assert_equals( testEl.properties.names.length, 1, 'outer names.length' );
  3232 	assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
  3233 	assert_true( !testEl.properties.names[1], 'outer names[1]' );
  3234 	assert_equals( testEl.firstChild.properties.length, 1, 'inner length' );
  3235 	assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
  3236 	assert_true( !testEl.firstChild.properties[1], 'inner properties[1]' );
  3237 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
  3238 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
  3239 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
  3240 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
  3241 	assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1]' );
  3242 	assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length' );
  3243 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
  3244 	assert_true( !testEl.firstChild.properties.names[1], 'inner names[1]' );
  3245 	document.body.appendChild(testEl);
  3246 	try {
  3247 		assert_equals( testEl.properties.length, 1, 'outer length when appended to document' );
  3248 		assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
  3249 		assert_true( !testEl.properties[1], 'outer properties[1] when appended to document' );
  3250 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
  3251 		assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
  3252 		assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
  3253 		assert_equals( testEl.properties.namedItem('bar').length, 0, 'outer bar.length when appended to document' );
  3254 		assert_true( !testEl.properties.namedItem('bar')[0], 'outer bar[0] when appended to document' );
  3255 		assert_equals( testEl.properties.names.length, 1, 'outer names.length when appended to document' );
  3256 		assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
  3257 		assert_true( !testEl.properties.names[1], 'outer names[1] when appended to document' );
  3258 		assert_equals( testEl.firstChild.properties.length, 1, 'inner length when appended to document' );
  3259 		assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
  3260 		assert_true( !testEl.firstChild.properties[1], 'inner properties[1] when appended to document' );
  3261 		assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
  3262 		assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
  3263 		assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
  3264 		assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
  3265 		assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1] when appended to document' );
  3266 		assert_equals( testEl.firstChild.properties.names.length, 1, 'inner names.length when appended to document' );
  3267 		assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
  3268 		assert_true( !testEl.firstChild.properties.names[1], 'inner names[1] when appended to document' );
  3269 	} catch(e) {
  3270 		document.body.removeChild(testEl);
  3271 		throw (e);
  3273 	document.body.removeChild(testEl);
  3274 }, 'nested itemref pointing to itself with child');
  3275 test(function () {
  3276 	//Each itemscope has one property, pointing to the other one
  3277 	var testEl = makeEl('div',{},'<div id="id1" itemprop="foo" itemscope itemref="id2"></div><div id="id2" itemprop="bar" itemscope itemref="id1"></div>');
  3278 	assert_equals( testEl.firstChild.properties.length, 1, 'id1 length' );
  3279 	assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0]' );
  3280 	assert_true( !testEl.firstChild.properties[1], 'id1 properties[1]' );
  3281 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length' );
  3282 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0]' );
  3283 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length' );
  3284 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0]' );
  3285 	assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1]' );
  3286 	assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length' );
  3287 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0]' );
  3288 	assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1]' );
  3289 	assert_equals( testEl.lastChild.properties.length, 1, 'id2 length' );
  3290 	assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0]' );
  3291 	assert_true( !testEl.lastChild.properties[1], 'id2 properties[1]' );
  3292 	assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length' );
  3293 	assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0]' );
  3294 	assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1]' );
  3295 	assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length' );
  3296 	assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0]' );
  3297 	assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length' );
  3298 	assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0]' );
  3299 	assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1]' );
  3300 	document.body.appendChild(testEl);
  3301 	try {
  3302 		assert_equals( testEl.firstChild.properties.length, 1, 'id1 length when appended to document' );
  3303 		assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0] when appended to document' );
  3304 		assert_true( !testEl.firstChild.properties[1], 'id1 properties[1] when appended to document' );
  3305 		assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length when appended to document' );
  3306 		assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0] when appended to document' );
  3307 		assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length when appended to document' );
  3308 		assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0] when appended to document' );
  3309 		assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1] when appended to document' );
  3310 		assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length when appended to document' );
  3311 		assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0] when appended to document' );
  3312 		assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1] when appended to document' );
  3313 		assert_equals( testEl.lastChild.properties.length, 1, 'id2 length when appended to document' );
  3314 		assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0] when appended to document' );
  3315 		assert_true( !testEl.lastChild.properties[1], 'id2 properties[1] when appended to document' );
  3316 		assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length when appended to document' );
  3317 		assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0] when appended to document' );
  3318 		assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1] when appended to document' );
  3319 		assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length when appended to document' );
  3320 		assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0] when appended to document' );
  3321 		assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length when appended to document' );
  3322 		assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0] when appended to document' );
  3323 		assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1] when appended to document' );
  3324 	} catch(e) {
  3325 		document.body.removeChild(testEl);
  3326 		throw (e);
  3328 	document.body.removeChild(testEl);
  3329 }, 'mutually referencing siblings');
  3330 test(function () {
  3331 	//Root has 2 properties, foo and bar
  3332 	//Each itemscope has one property, pointing to the other one
  3333 	var testEl = makeEl('div',{itemscope:'itemscope'},'<div id="id1" itemprop="foo" itemscope itemref="id2"></div><div id="id2" itemprop="bar" itemscope itemref="id1"></div>');
  3334 	assert_equals( testEl.properties.length, 2, 'root length' );
  3335 	assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0]' );
  3336 	assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1]' );
  3337 	assert_true( !testEl.properties[2], 'root properties[2]' );
  3338 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length' );
  3339 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0]' );
  3340 	assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1]' );
  3341 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length' );
  3342 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0]' );
  3343 	assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1]' );
  3344 	assert_equals( testEl.properties.names.length, 2, 'root names.length' );
  3345 	assert_equals( testEl.properties.names[0], 'foo', 'root names[0]' );
  3346 	assert_equals( testEl.properties.names[1], 'bar', 'root names[1]' );
  3347 	assert_true( !testEl.properties.names[2], 'root names[2]' );
  3348 	assert_equals( testEl.firstChild.properties.length, 1, 'id1 length' );
  3349 	assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0]' );
  3350 	assert_true( !testEl.firstChild.properties[1], 'id1 properties[1]' );
  3351 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length' );
  3352 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0]' );
  3353 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length' );
  3354 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0]' );
  3355 	assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1]' );
  3356 	assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length' );
  3357 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0]' );
  3358 	assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1]' );
  3359 	assert_equals( testEl.lastChild.properties.length, 1, 'id2 length' );
  3360 	assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0]' );
  3361 	assert_true( !testEl.lastChild.properties[1], 'id2 properties[1]' );
  3362 	assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length' );
  3363 	assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0]' );
  3364 	assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1]' );
  3365 	assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length' );
  3366 	assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0]' );
  3367 	assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length' );
  3368 	assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0]' );
  3369 	assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1]' );
  3370 	document.body.appendChild(testEl);
  3371 	try {
  3372 		assert_equals( testEl.properties.length, 2, 'root length when appended to document' );
  3373 		assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0] when appended to document' );
  3374 		assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1] when appended to document' );
  3375 		assert_true( !testEl.properties[2], 'root properties[2] when appended to document' );
  3376 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length when appended to document' );
  3377 		assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0] when appended to document' );
  3378 		assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1] when appended to document' );
  3379 		assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length when appended to document' );
  3380 		assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0] when appended to document' );
  3381 		assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1] when appended to document' );
  3382 		assert_equals( testEl.properties.names.length, 2, 'root names.length when appended to document' );
  3383 		assert_equals( testEl.properties.names[0], 'foo', 'root names[0] when appended to document' );
  3384 		assert_equals( testEl.properties.names[1], 'bar', 'root names[1] when appended to document' );
  3385 		assert_true( !testEl.properties.names[2], 'root names[2] when appended to document' );
  3386 		assert_equals( testEl.firstChild.properties.length, 1, 'id1 length when appended to document' );
  3387 		assert_equals( testEl.firstChild.properties[0], testEl.lastChild, 'id1 properties[0] when appended to document' );
  3388 		assert_true( !testEl.firstChild.properties[1], 'id1 properties[1] when appended to document' );
  3389 		assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'id1 foo.length when appended to document' );
  3390 		assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'id1 foo[0] when appended to document' );
  3391 		assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'id1 bar.length when appended to document' );
  3392 		assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.lastChild, 'id1 bar[0] when appended to document' );
  3393 		assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'id1 bar[1] when appended to document' );
  3394 		assert_equals( testEl.firstChild.properties.names.length, 1, 'id1 names.length when appended to document' );
  3395 		assert_equals( testEl.firstChild.properties.names[0], 'bar', 'id1 names[0] when appended to document' );
  3396 		assert_true( !testEl.firstChild.properties.names[1], 'id1 names[1] when appended to document' );
  3397 		assert_equals( testEl.lastChild.properties.length, 1, 'id2 length when appended to document' );
  3398 		assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'id2 properties[0] when appended to document' );
  3399 		assert_true( !testEl.lastChild.properties[1], 'id2 properties[1] when appended to document' );
  3400 		assert_equals( testEl.lastChild.properties.namedItem('foo').length, 1, 'id2 foo.length when appended to document' );
  3401 		assert_equals( testEl.lastChild.properties.namedItem('foo')[0], testEl.firstChild, 'id2 foo[0] when appended to document' );
  3402 		assert_true( !testEl.lastChild.properties.namedItem('foo')[1], 'id2 foo[1] when appended to document' );
  3403 		assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'id2 bar.length when appended to document' );
  3404 		assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'id2 bar[0] when appended to document' );
  3405 		assert_equals( testEl.lastChild.properties.names.length, 1, 'id2 names.length when appended to document' );
  3406 		assert_equals( testEl.lastChild.properties.names[0], 'foo', 'id2 names[0] when appended to document' );
  3407 		assert_true( !testEl.lastChild.properties.names[1], 'id2 names[1] when appended to document' );
  3408 	} catch(e) {
  3409 		document.body.removeChild(testEl);
  3410 		throw (e);
  3412 	document.body.removeChild(testEl);
  3413 }, 'mutually referencing siblings with item parent');
  3414 test(function () {
  3415 	//Root has two properties, foo and bar
  3416 	//Bar has two properties, baz and qux
  3417 	//Qux has one property, bar
  3418 	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>');
  3419 	assert_equals( testEl.properties.length, 2, 'root length' );
  3420 	assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0]' );
  3421 	assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1]' );
  3422 	assert_true( !testEl.properties[2], 'root properties[2]' );
  3423 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length' );
  3424 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0]' );
  3425 	assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1]' );
  3426 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length' );
  3427 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0]' );
  3428 	assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1]' );
  3429 	assert_equals( testEl.properties.namedItem('baz').length, 0, 'root baz.length' );
  3430 	assert_true( !testEl.properties.namedItem('baz')[0], 'root baz[0]' );
  3431 	assert_equals( testEl.properties.namedItem('qux').length, 0, 'root qux.length' );
  3432 	assert_true( !testEl.properties.namedItem('qux')[0], 'root qux[0]' );
  3433 	assert_equals( testEl.properties.names.length, 2, 'root names.length' );
  3434 	assert_equals( testEl.properties.names[0], 'foo', 'root names[0]' );
  3435 	assert_equals( testEl.properties.names[1], 'bar', 'root names[1]' );
  3436 	assert_true( !testEl.properties.names[2], 'root names[2]' );
  3437 	assert_equals( testEl.lastChild.properties.length, 2, 'bar length' );
  3438 	assert_equals( testEl.lastChild.properties[0], testEl.lastChild.firstChild, 'bar properties[0]' );
  3439 	assert_equals( testEl.lastChild.properties[1], testEl.lastChild.lastChild, 'bar properties[1]' );
  3440 	assert_true( !testEl.lastChild.properties[2], 'bar properties[2]' );
  3441 	assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'bar foo.length' );
  3442 	assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'bar foo[0]' );
  3443 	assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'bar bar.length' );
  3444 	assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'bar bar[0]' );
  3445 	assert_equals( testEl.lastChild.properties.namedItem('baz').length, 1, 'bar baz.length' );
  3446 	assert_equals( testEl.lastChild.properties.namedItem('baz')[0], testEl.lastChild.firstChild, 'bar baz[0]' );
  3447 	assert_true( !testEl.lastChild.properties.namedItem('baz')[1], 'bar baz[1]' );
  3448 	assert_equals( testEl.lastChild.properties.namedItem('qux').length, 1, 'bar qux.length' );
  3449 	assert_equals( testEl.lastChild.properties.namedItem('qux')[0], testEl.lastChild.lastChild, 'bar qux[0]' );
  3450 	assert_true( !testEl.lastChild.properties.namedItem('qux')[1], 'bar qux[1]' );
  3451 	assert_equals( testEl.lastChild.properties.names.length, 2, 'bar names.length' );
  3452 	assert_equals( testEl.lastChild.properties.names[0], 'baz', 'bar names[0]' );
  3453 	assert_equals( testEl.lastChild.properties.names[1], 'qux', 'bar names[1]' );
  3454 	assert_true( !testEl.lastChild.properties.names[2], 'bar names[2]' );
  3455 	assert_equals( testEl.lastChild.lastChild.properties.length, 1, 'qux length' );
  3456 	assert_equals( testEl.lastChild.lastChild.properties[0], testEl.lastChild, 'qux properties[0]' );
  3457 	assert_true( !testEl.lastChild.lastChild.properties[1], 'qux properties[1]' );
  3458 	assert_equals( testEl.lastChild.lastChild.properties.namedItem('foo').length, 0, 'qux foo.length' );
  3459 	assert_true( !testEl.lastChild.lastChild.properties.namedItem('foo')[0], 'qux foo[0]' );
  3460 	assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar').length, 1, 'qux bar.length' );
  3461 	assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar')[0], testEl.lastChild, 'qux bar[0]' );
  3462 	assert_true( !testEl.lastChild.lastChild.properties.namedItem('bar')[1], 'qux bar[1]' );
  3463 	assert_equals( testEl.lastChild.lastChild.properties.namedItem('baz').length, 0, 'qux baz.length' );
  3464 	assert_true( !testEl.lastChild.lastChild.properties.namedItem('baz')[0], 'qux baz[0]' );
  3465 	assert_equals( testEl.lastChild.lastChild.properties.namedItem('qux').length, 0, 'qux qux.length' );
  3466 	assert_true( !testEl.lastChild.lastChild.properties.namedItem('qux')[0], 'qux qux[0]' );
  3467 	assert_equals( testEl.lastChild.lastChild.properties.names.length, 1, 'qux names.length' );
  3468 	assert_equals( testEl.lastChild.lastChild.properties.names[0], 'bar', 'qux names[0]' );
  3469 	assert_true( !testEl.lastChild.lastChild.properties.names[1], 'qux names[1]' );
  3470 	document.body.appendChild(testEl);
  3471 	try {
  3472 		assert_equals( testEl.properties.length, 2, 'root length when appended to document' );
  3473 		assert_equals( testEl.properties[0], testEl.firstChild, 'root properties[0] when appended to document' );
  3474 		assert_equals( testEl.properties[1], testEl.lastChild, 'root properties[1] when appended to document' );
  3475 		assert_true( !testEl.properties[2], 'root properties[2] when appended to document' );
  3476 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'root foo.length when appended to document' );
  3477 		assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'root foo[0] when appended to document' );
  3478 		assert_true( !testEl.properties.namedItem('foo')[1], 'root foo[1] when appended to document' );
  3479 		assert_equals( testEl.properties.namedItem('bar').length, 1, 'root bar.length when appended to document' );
  3480 		assert_equals( testEl.properties.namedItem('bar')[0], testEl.lastChild, 'root bar[0] when appended to document' );
  3481 		assert_true( !testEl.properties.namedItem('bar')[1], 'root bar[1] when appended to document' );
  3482 		assert_equals( testEl.properties.namedItem('baz').length, 0, 'root baz.length when appended to document' );
  3483 		assert_true( !testEl.properties.namedItem('baz')[0], 'root baz[0] when appended to document' );
  3484 		assert_equals( testEl.properties.namedItem('qux').length, 0, 'root qux.length when appended to document' );
  3485 		assert_true( !testEl.properties.namedItem('qux')[0], 'root qux[0] when appended to document' );
  3486 		assert_equals( testEl.properties.names.length, 2, 'root names.length when appended to document' );
  3487 		assert_equals( testEl.properties.names[0], 'foo', 'root names[0] when appended to document' );
  3488 		assert_equals( testEl.properties.names[1], 'bar', 'root names[1] when appended to document' );
  3489 		assert_true( !testEl.properties.names[2], 'root names[2] when appended to document' );
  3490 		assert_equals( testEl.lastChild.properties.length, 2, 'bar length when appended to document' );
  3491 		assert_equals( testEl.lastChild.properties[0], testEl.lastChild.firstChild, 'bar properties[0] when appended to document' );
  3492 		assert_equals( testEl.lastChild.properties[1], testEl.lastChild.lastChild, 'bar properties[1] when appended to document' );
  3493 		assert_true( !testEl.lastChild.properties[2], 'bar properties[2] when appended to document' );
  3494 		assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'bar foo.length when appended to document' );
  3495 		assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'bar foo[0] when appended to document' );
  3496 		assert_equals( testEl.lastChild.properties.namedItem('bar').length, 0, 'bar bar.length when appended to document' );
  3497 		assert_true( !testEl.lastChild.properties.namedItem('bar')[0], 'bar bar[0] when appended to document' );
  3498 		assert_equals( testEl.lastChild.properties.namedItem('baz').length, 1, 'bar baz.length when appended to document' );
  3499 		assert_equals( testEl.lastChild.properties.namedItem('baz')[0], testEl.lastChild.firstChild, 'bar baz[0] when appended to document' );
  3500 		assert_true( !testEl.lastChild.properties.namedItem('baz')[1], 'bar baz[1] when appended to document' );
  3501 		assert_equals( testEl.lastChild.properties.namedItem('qux').length, 1, 'bar qux.length when appended to document' );
  3502 		assert_equals( testEl.lastChild.properties.namedItem('qux')[0], testEl.lastChild.lastChild, 'bar qux[0] when appended to document' );
  3503 		assert_true( !testEl.lastChild.properties.namedItem('qux')[1], 'bar qux[1] when appended to document' );
  3504 		assert_equals( testEl.lastChild.properties.names.length, 2, 'bar names.length when appended to document' );
  3505 		assert_equals( testEl.lastChild.properties.names[0], 'baz', 'bar names[0] when appended to document' );
  3506 		assert_equals( testEl.lastChild.properties.names[1], 'qux', 'bar names[1] when appended to document' );
  3507 		assert_true( !testEl.lastChild.properties.names[2], 'bar names[2] when appended to document' );
  3508 		assert_equals( testEl.lastChild.lastChild.properties.length, 1, 'qux length when appended to document' );
  3509 		assert_equals( testEl.lastChild.lastChild.properties[0], testEl.lastChild, 'qux properties[0] when appended to document' );
  3510 		assert_true( !testEl.lastChild.lastChild.properties[1], 'qux properties[1] when appended to document' );
  3511 		assert_equals( testEl.lastChild.lastChild.properties.namedItem('foo').length, 0, 'qux foo.length when appended to document' );
  3512 		assert_true( !testEl.lastChild.lastChild.properties.namedItem('foo')[0], 'qux foo[0] when appended to document' );
  3513 		assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar').length, 1, 'qux bar.length when appended to document' );
  3514 		assert_equals( testEl.lastChild.lastChild.properties.namedItem('bar')[0], testEl.lastChild, 'qux bar[0] when appended to document' );
  3515 		assert_true( !testEl.lastChild.lastChild.properties.namedItem('bar')[1], 'qux bar[1] when appended to document' );
  3516 		assert_equals( testEl.lastChild.lastChild.properties.namedItem('baz').length, 0, 'qux baz.length when appended to document' );
  3517 		assert_true( !testEl.lastChild.lastChild.properties.namedItem('baz')[0], 'qux baz[0] when appended to document' );
  3518 		assert_equals( testEl.lastChild.lastChild.properties.namedItem('qux').length, 0, 'qux qux.length when appended to document' );
  3519 		assert_true( !testEl.lastChild.lastChild.properties.namedItem('qux')[0], 'qux qux[0] when appended to document' );
  3520 		assert_equals( testEl.lastChild.lastChild.properties.names.length, 1, 'qux names.length when appended to document' );
  3521 		assert_equals( testEl.lastChild.lastChild.properties.names[0], 'bar', 'qux names[0] when appended to document' );
  3522 		assert_true( !testEl.lastChild.lastChild.properties.names[1], 'qux names[1] when appended to document' );
  3523 	} catch(e) {
  3524 		document.body.removeChild(testEl);
  3525 		throw (e);
  3527 	document.body.removeChild(testEl);
  3528 }, 'itemref referencing parent item');
  3529 test(function () {
  3530 	//foo has one property, bar
  3531 	var testEl = makeEl('div',{id:'id1'},'<div itemprop="bar"></div><div itemscope itemref="id1" itemprop="foo"></div>');
  3532 	assert_equals( testEl.lastChild.properties.length, 1, 'length' );
  3533 	assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'properties[0]' );
  3534 	assert_true( !testEl.lastChild.properties[1], 'properties[1]' );
  3535 	assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'foo.length' );
  3536 	assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'foo[0]' );
  3537 	assert_equals( testEl.lastChild.properties.namedItem('bar').length, 1, 'bar.length' );
  3538 	assert_equals( testEl.lastChild.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0]' );
  3539 	assert_true( !testEl.lastChild.properties.namedItem('bar')[1], 'bar[1]' );
  3540 	assert_equals( testEl.lastChild.properties.names.length, 1, 'names.length' );
  3541 	assert_equals( testEl.lastChild.properties.names[0], 'bar', 'names[0]' );
  3542 	assert_true( !testEl.lastChild.properties.names[1], 'names[1]' );
  3543 	document.body.appendChild(testEl);
  3544 	try {
  3545 		assert_equals( testEl.lastChild.properties.length, 1, 'length when appended to document' );
  3546 		assert_equals( testEl.lastChild.properties[0], testEl.firstChild, 'properties[0] when appended to document' );
  3547 		assert_true( !testEl.lastChild.properties[1], 'properties[1] when appended to document' );
  3548 		assert_equals( testEl.lastChild.properties.namedItem('foo').length, 0, 'foo.length when appended to document' );
  3549 		assert_true( !testEl.lastChild.properties.namedItem('foo')[0], 'foo[0] when appended to document' );
  3550 		assert_equals( testEl.lastChild.properties.namedItem('bar').length, 1, 'bar.length when appended to document' );
  3551 		assert_equals( testEl.lastChild.properties.namedItem('bar')[0], testEl.firstChild, 'bar[0] when appended to document' );
  3552 		assert_true( !testEl.lastChild.properties.namedItem('bar')[1], 'bar[1] when appended to document' );
  3553 		assert_equals( testEl.lastChild.properties.names.length, 1, 'names.length when appended to document' );
  3554 		assert_equals( testEl.lastChild.properties.names[0], 'bar', 'names[0] when appended to document' );
  3555 		assert_true( !testEl.lastChild.properties.names[1], 'names[1] when appended to document' );
  3556 	} catch(e) {
  3557 		document.body.removeChild(testEl);
  3558 		throw (e);
  3560 	document.body.removeChild(testEl);
  3561 }, 'itemref referencing parent without itemscope');
  3562 test(function () {
  3563 	var testDiv = makeEl('div', {itemprop:'bar', id:'foo'}, '');
  3564 	var testSpan = makeEl('span', {itemscope:'itemscope', itemref: 'foo', id: 'foo'}, '');
  3565 	document.body.appendChild(testDiv);
  3566 	document.body.appendChild(testSpan);
  3567 	assert_equals(testSpan.properties.length, 1, 'has one property');
  3568 	assert_equals(testSpan.properties[0], testDiv, 'has first property');
  3569 	assert_equals(testSpan.properties.item(0), testDiv, 'has first property');
  3570 	assert_equals(testSpan.properties.namedItem('bar').length, 1, 'has 1 foo property');
  3571 	assert_equals(testSpan.properties.namedItem('bar').item(0), testDiv, 'div is foo property');
  3572 	assert_equals(testSpan.properties.names.length, 1, 'only has one property');
  3573 	document.body.removeChild(testDiv);
  3574 	document.body.removeChild(testSpan);
  3575 }, 'itemref referencing element with same id');
  3576 test(function () {
  3577 	//Root has three properties, foo, bar and baz
  3578 	//Foo has two properties, bar and baz
  3579 	var testEl = makeEl('div',{itemscope:'itemscope',itemref:'id1'},'<div itemscope itemprop="foo"><div itemprop="bar" id="id1"><div itemprop="baz"></div></div></div>');
  3580 	assert_equals( testEl.properties.length, 3, 'outer length' );
  3581 	assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0]' );
  3582 	assert_equals( testEl.properties[1], testEl.firstChild.firstChild, 'outer properties[1]' );
  3583 	assert_equals( testEl.properties[2], testEl.firstChild.firstChild.firstChild, 'outer properties[2]' );
  3584 	assert_true( !testEl.properties[3], 'outer properties[3]' );
  3585 	assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length' );
  3586 	assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0]' );
  3587 	assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1]' );
  3588 	assert_equals( testEl.properties.namedItem('bar').length, 1, 'outer bar.length' );
  3589 	assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'outer bar[0]' );
  3590 	assert_true( !testEl.properties.namedItem('bar')[1], 'outer bar[1]' );
  3591 	assert_equals( testEl.properties.namedItem('baz').length, 1, 'outer baz.length' );
  3592 	assert_equals( testEl.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'outer baz[0]' );
  3593 	assert_true( !testEl.properties.namedItem('baz')[1], 'outer baz[1]' );
  3594 	assert_equals( testEl.properties.names.length, 3, 'outer names.length' );
  3595 	assert_equals( testEl.properties.names[0], 'foo', 'outer names[0]' );
  3596 	assert_equals( testEl.properties.names[1], 'bar', 'outer names[1]' );
  3597 	assert_equals( testEl.properties.names[2], 'baz', 'outer names[2]' );
  3598 	assert_true( !testEl.properties.names[3], 'outer names[3]' );
  3599 	assert_equals( testEl.firstChild.properties.length, 2, 'inner length' );
  3600 	assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0]' );
  3601 	assert_equals( testEl.firstChild.properties[1], testEl.firstChild.firstChild.firstChild, 'inner properties[1]' );
  3602 	assert_true( !testEl.firstChild.properties[2], 'inner properties[2]' );
  3603 	assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length' );
  3604 	assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0]' );
  3605 	assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length' );
  3606 	assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0]' );
  3607 	assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1]' );
  3608 	assert_equals( testEl.firstChild.properties.namedItem('baz').length, 1, 'inner baz.length' );
  3609 	assert_equals( testEl.firstChild.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'inner baz[0]' );
  3610 	assert_true( !testEl.firstChild.properties.namedItem('baz')[1], 'inner baz[1]' );
  3611 	assert_equals( testEl.firstChild.properties.names.length, 2, 'inner names.length' );
  3612 	assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0]' );
  3613 	assert_equals( testEl.firstChild.properties.names[1], 'baz', 'inner names[1]' );
  3614 	assert_true( !testEl.firstChild.properties.names[2], 'inner names[2]' );
  3615 	document.body.appendChild(testEl);
  3616 	try {
  3617 		assert_equals( testEl.properties.length, 3, 'outer length when appended to document' );
  3618 		assert_equals( testEl.properties[0], testEl.firstChild, 'outer properties[0] when appended to document' );
  3619 		assert_equals( testEl.properties[1], testEl.firstChild.firstChild, 'outer properties[1] when appended to document' );
  3620 		assert_equals( testEl.properties[2], testEl.firstChild.firstChild.firstChild, 'outer properties[2] when appended to document' );
  3621 		assert_true( !testEl.properties[3], 'outer properties[3] when appended to document' );
  3622 		assert_equals( testEl.properties.namedItem('foo').length, 1, 'outer foo.length when appended to document' );
  3623 		assert_equals( testEl.properties.namedItem('foo')[0], testEl.firstChild, 'outer foo[0] when appended to document' );
  3624 		assert_true( !testEl.properties.namedItem('foo')[1], 'outer foo[1] when appended to document' );
  3625 		assert_equals( testEl.properties.namedItem('bar').length, 1, 'outer bar.length when appended to document' );
  3626 		assert_equals( testEl.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'outer bar[0] when appended to document' );
  3627 		assert_true( !testEl.properties.namedItem('bar')[1], 'outer bar[1] when appended to document' );
  3628 		assert_equals( testEl.properties.namedItem('baz').length, 1, 'outer baz.length when appended to document' );
  3629 		assert_equals( testEl.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'outer baz[0] when appended to document' );
  3630 		assert_true( !testEl.properties.namedItem('baz')[1], 'outer baz[1] when appended to document' );
  3631 		assert_equals( testEl.properties.names.length, 3, 'outer names.length when appended to document' );
  3632 		assert_equals( testEl.properties.names[0], 'foo', 'outer names[0] when appended to document' );
  3633 		assert_equals( testEl.properties.names[1], 'bar', 'outer names[1] when appended to document' );
  3634 		assert_equals( testEl.properties.names[2], 'baz', 'outer names[2] when appended to document' );
  3635 		assert_true( !testEl.properties.names[3], 'outer names[3] when appended to document' );
  3636 		assert_equals( testEl.firstChild.properties.length, 2, 'inner length when appended to document' );
  3637 		assert_equals( testEl.firstChild.properties[0], testEl.firstChild.firstChild, 'inner properties[0] when appended to document' );
  3638 		assert_equals( testEl.firstChild.properties[1], testEl.firstChild.firstChild.firstChild, 'inner properties[1] when appended to document' );
  3639 		assert_true( !testEl.firstChild.properties[2], 'inner properties[2] when appended to document' );
  3640 		assert_equals( testEl.firstChild.properties.namedItem('foo').length, 0, 'inner foo.length when appended to document' );
  3641 		assert_true( !testEl.firstChild.properties.namedItem('foo')[0], 'inner foo[0] when appended to document' );
  3642 		assert_equals( testEl.firstChild.properties.namedItem('bar').length, 1, 'inner bar.length when appended to document' );
  3643 		assert_equals( testEl.firstChild.properties.namedItem('bar')[0], testEl.firstChild.firstChild, 'inner bar[0] when appended to document' );
  3644 		assert_true( !testEl.firstChild.properties.namedItem('bar')[1], 'inner bar[1] when appended to document' );
  3645 		assert_equals( testEl.firstChild.properties.namedItem('baz').length, 1, 'inner baz.length when appended to document' );
  3646 		assert_equals( testEl.firstChild.properties.namedItem('baz')[0], testEl.firstChild.firstChild.firstChild, 'inner baz[0] when appended to document' );
  3647 		assert_true( !testEl.firstChild.properties.namedItem('baz')[1], 'inner baz[1] when appended to document' );
  3648 		assert_equals( testEl.firstChild.properties.names.length, 2, 'inner names.length when appended to document' );
  3649 		assert_equals( testEl.firstChild.properties.names[0], 'bar', 'inner names[0] when appended to document' );
  3650 		assert_equals( testEl.firstChild.properties.names[1], 'baz', 'inner names[1] when appended to document' );
  3651 		assert_true( !testEl.firstChild.properties.names[2], 'inner names[2] when appended to document' );
  3652 	} catch(e) {
  3653 		document.body.removeChild(testEl);
  3654 		throw (e);
  3656 	document.body.removeChild(testEl);
  3657 }, 'itemref pointing to child of nested itemscope');
  3659 		</script>
  3660 	</body>
  3661 </html>

mercurial