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

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:08fae416755e
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. */
24
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 }
38
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');
166
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');
216
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');
511
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');
796
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');
838
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;
1113 }
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;
1123 }
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');
1128
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 );
1420 }
1421 }, 'dynamic changes of itemscope should change the value exposed through itemValue');
1422
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 );
1453 }
1454 }, 'dynamic changes of itemprop should change the value exposed through itemValue');
1455
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;
1477 }
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;
1991 }
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 () {
2047
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 );
2411 }
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;
2439 }
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 );
2445 }
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;
2467 }
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;
2529 }
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');
2887
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];
2924 }
2925 }
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+']' );
2932 }
2933 }
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+']' );
2938 }
2939 }
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];
2974 }
2975 }
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+']' );
2982 }
2983 }
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+']' );
2988 }
2989 }
2990 }, 'collections must survive the item\'s removal from the document');
2991
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');
3006
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');
3031
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);
3111 }
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);
3161 }
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);
3184 }
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);
3217 }
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);
3272 }
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);
3327 }
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);
3411 }
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);
3526 }
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);
3559 }
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);
3655 }
3656 document.body.removeChild(testEl);
3657 }, 'itemref pointing to child of nested itemscope');
3658
3659 </script>
3660 </body>
3661 </html>

mercurial