OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library ElementTest; |
| 6 |
| 7 import 'package:unittest/unittest.dart'; |
| 8 import 'package:unittest/html_individual_config.dart'; |
| 9 import 'dart:async'; |
| 10 import 'dart:html'; |
| 11 import 'dart:svg' as svg; |
| 12 import 'utils.dart'; |
| 13 |
| 14 expectLargeRect(Rectangle rect) { |
| 15 expect(rect.top, 0); |
| 16 expect(rect.left, 0); |
| 17 expect(rect.width, greaterThan(100)); |
| 18 expect(rect.height, greaterThan(100)); |
| 19 expect(rect.bottom, rect.top + rect.height); |
| 20 expect(rect.right, rect.left + rect.width); |
| 21 } |
| 22 |
| 23 void testUnsupported(String name, void f()) { |
| 24 test(name, () { |
| 25 expect(f, throwsUnsupportedError); |
| 26 }); |
| 27 } |
| 28 |
| 29 main() { |
| 30 useHtmlIndividualConfiguration(); |
| 31 |
| 32 var isHRElement = predicate((x) => x is HRElement, 'is a HRElement'); |
| 33 var isBRElement = predicate((x) => x is BRElement, 'is a BRElement'); |
| 34 var isInputElement = |
| 35 predicate((x) => x is InputElement, 'is an InputElement'); |
| 36 var isImageElement = |
| 37 predicate((x) => x is ImageElement, 'is an ImageElement'); |
| 38 var isSpanElement = predicate((x) => x is SpanElement, 'is a SpanElement'); |
| 39 var isAnchorElement = |
| 40 predicate((x) => x is AnchorElement, 'is an AnchorElement'); |
| 41 var isElementList = |
| 42 predicate((x) => x is List<Element>, 'is a List<Element>'); |
| 43 var isElementIterable = |
| 44 predicate((x) => x is Iterable<Element>, 'is an Iterable<Element>'); |
| 45 var isHeadingElement = |
| 46 predicate((x) => x is HeadingElement, 'is a HeadingElement'); |
| 47 |
| 48 Element makeElement() => new Element.tag('div'); |
| 49 |
| 50 Element makeElementWithChildren() => |
| 51 new Element.html("<div><br/><img/><input/></div>"); |
| 52 |
| 53 group('position', () { |
| 54 test('computedStyle', () { |
| 55 final element = document.body; |
| 56 var style = element.getComputedStyle(); |
| 57 expect(style.getPropertyValue('left'), 'auto'); |
| 58 }); |
| 59 |
| 60 test('client position synchronous', () { |
| 61 final container = new Element.tag("div"); |
| 62 container.style.position = 'absolute'; |
| 63 container.style.top = '8px'; |
| 64 container.style.left = '9px'; |
| 65 final element = new Element.tag("div"); |
| 66 element.style.width = '200px'; |
| 67 element.style.height = '200px'; |
| 68 container.children.add(element); |
| 69 document.body.children.add(container); |
| 70 |
| 71 expect(element.client.width, greaterThan(100)); |
| 72 expect(element.client.height, greaterThan(100)); |
| 73 expect(element.offset.width, greaterThan(100)); |
| 74 expect(element.offset.height, greaterThan(100)); |
| 75 expect(element.scrollWidth, greaterThan(100)); |
| 76 expect(element.scrollHeight, greaterThan(100)); |
| 77 expect(element.getBoundingClientRect().left, 9); |
| 78 expect(element.getBoundingClientRect().top, 8); |
| 79 |
| 80 expect(element.documentOffset.x, 9); |
| 81 expect(element.documentOffset.y, 8); |
| 82 container.remove(); |
| 83 }); |
| 84 }); |
| 85 |
| 86 group('constructors', () { |
| 87 test('error', () { |
| 88 expect(() => new Element.html('<br/><br/>'), throwsStateError); |
| 89 }); |
| 90 |
| 91 test('.html has no parent', |
| 92 () => expect(new Element.html('<br/>').parent, isNull)); |
| 93 |
| 94 test('.html table', () { |
| 95 // http://developers.whatwg.org/tabular-data.html#tabular-data |
| 96 var node = new Element.html(''' |
| 97 <table> |
| 98 <caption>Characteristics with positive and negative sides</caption> |
| 99 <thead> |
| 100 <tr> |
| 101 <th id="n"> Negative |
| 102 <th> Characteristic |
| 103 <th> Positive |
| 104 <tbody> |
| 105 <tr> |
| 106 <td headers="n r1"> Sad |
| 107 <th id="r1"> Mood |
| 108 <td> Happy |
| 109 <tr> |
| 110 <td headers="n r2"> Failing |
| 111 <th id="r2"> Grade |
| 112 <td> Passing |
| 113 </table>'''); |
| 114 expect(node, predicate((x) => x is TableElement, 'is a TableElement')); |
| 115 expect(node.tagName, 'TABLE'); |
| 116 expect(node.parent, isNull); |
| 117 expect(node.caption.innerHtml, |
| 118 'Characteristics with positive and negative sides'); |
| 119 expect(node.tHead.rows.length, 1); |
| 120 expect(node.tHead.rows[0].cells.length, 3); |
| 121 expect(node.tBodies.length, 1); |
| 122 expect(node.tBodies[0].rows.length, 2); |
| 123 expect(node.tBodies[0].rows[1].cells.map((c) => c.innerHtml), |
| 124 [' Failing\n ', ' Grade\n ', ' Passing\n']); |
| 125 }); |
| 126 |
| 127 test('.html caption', () { |
| 128 var table = new TableElement(); |
| 129 var node = table.createFragment('<caption><p>Table 1.').nodes.single; |
| 130 expect( |
| 131 node, |
| 132 predicate( |
| 133 (x) => x is TableCaptionElement, 'is a TableCaptionElement')); |
| 134 expect(node.tagName, 'CAPTION'); |
| 135 expect(node.parent, isNull); |
| 136 expect(node.innerHtml, '<p>Table 1.</p>'); |
| 137 }); |
| 138 |
| 139 test('.html colgroup', () { |
| 140 var table = new TableElement(); |
| 141 var node = |
| 142 table.createFragment('<colgroup> <col> <col> <col>').nodes.single; |
| 143 expect( |
| 144 node, predicate((x) => x is TableColElement, 'is a TableColElement')); |
| 145 expect(node.tagName, 'COLGROUP'); |
| 146 expect(node.parent, isNull); |
| 147 expect(node.innerHtml, ' <col> <col> <col>'); |
| 148 }); |
| 149 |
| 150 test('.html tbody', () { |
| 151 var innerHtml = '<tr><td headers="n r1">Sad</td><td>Happy</td></tr>'; |
| 152 var table = new TableElement(); |
| 153 var node = table.createFragment('<tbody>$innerHtml').nodes.single; |
| 154 expect( |
| 155 node, |
| 156 predicate( |
| 157 (x) => x is TableSectionElement, 'is a TableSectionElement')); |
| 158 expect(node.tagName, 'TBODY'); |
| 159 expect(node.parent, isNull); |
| 160 expect(node.rows.length, 1); |
| 161 expect(node.rows[0].cells.length, 2); |
| 162 expect(node.innerHtml, innerHtml); |
| 163 }); |
| 164 |
| 165 test('.html thead', () { |
| 166 var innerHtml = '<tr><th id="n">Negative</th><th>Positive</th></tr>'; |
| 167 var table = new TableElement(); |
| 168 var node = table.createFragment('<thead>$innerHtml').nodes.single; |
| 169 expect( |
| 170 node, |
| 171 predicate( |
| 172 (x) => x is TableSectionElement, 'is a TableSectionElement')); |
| 173 expect(node.tagName, 'THEAD'); |
| 174 expect(node.parent, isNull); |
| 175 expect(node.rows.length, 1); |
| 176 expect(node.rows[0].cells.length, 2); |
| 177 expect(node.innerHtml, innerHtml); |
| 178 }); |
| 179 |
| 180 test('.html tfoot', () { |
| 181 var innerHtml = '<tr><th>percentage</th><td>34.3%</td></tr>'; |
| 182 var table = new TableElement(); |
| 183 var node = table.createFragment('<tfoot>$innerHtml').nodes.single; |
| 184 expect( |
| 185 node, |
| 186 predicate( |
| 187 (x) => x is TableSectionElement, 'is a TableSectionElement')); |
| 188 expect(node.tagName, 'TFOOT'); |
| 189 expect(node.parent, isNull); |
| 190 expect(node.rows.length, 1); |
| 191 expect(node.rows[0].cells.length, 2); |
| 192 expect(node.innerHtml, innerHtml); |
| 193 }); |
| 194 |
| 195 test('.html tr', () { |
| 196 var table = new TableElement(); |
| 197 document.body.append(table); |
| 198 var tBody = table.createTBody(); |
| 199 var node = tBody.createFragment('<tr><td>foo<td>bar').nodes.single; |
| 200 expect( |
| 201 node, predicate((x) => x is TableRowElement, 'is a TableRowElement')); |
| 202 expect(node.tagName, 'TR'); |
| 203 expect(node.parent, isNull); |
| 204 expect(node.cells.map((c) => c.innerHtml), ['foo', 'bar']); |
| 205 }); |
| 206 |
| 207 test('.html td', () { |
| 208 var table = new TableElement(); |
| 209 document.body.append(table); |
| 210 var tBody = table.createTBody(); |
| 211 var tRow = tBody.addRow(); |
| 212 var node = tRow.createFragment('<td>foobar').nodes.single; |
| 213 expect(node, |
| 214 predicate((x) => x is TableCellElement, 'is a TableCellElement')); |
| 215 expect(node.tagName, 'TD'); |
| 216 expect(node.parent, isNull); |
| 217 expect(node.innerHtml, 'foobar'); |
| 218 }); |
| 219 |
| 220 test('.html th', () { |
| 221 var table = new TableElement(); |
| 222 document.body.append(table); |
| 223 var tBody = table.createTBody(); |
| 224 var tRow = tBody.addRow(); |
| 225 var node = tRow.createFragment('<th>foobar').nodes.single; |
| 226 expect(node, |
| 227 predicate((x) => x is TableCellElement, 'is a TableCellElement')); |
| 228 expect(node.tagName, 'TH'); |
| 229 expect(node.parent, isNull); |
| 230 expect(node.innerHtml, 'foobar'); |
| 231 }); |
| 232 |
| 233 test('.html can fire events', () { |
| 234 var e = new Element.html('<button>aha</button>'); |
| 235 var gotEvent = false; |
| 236 e.onClick.listen((_) { |
| 237 gotEvent = true; |
| 238 }); |
| 239 e.click(); |
| 240 expect(gotEvent, isTrue, reason: 'click should have raised click event'); |
| 241 }); |
| 242 }); |
| 243 |
| 244 group('eventListening', () { |
| 245 test('streams', () { |
| 246 final target = new TextAreaElement(); |
| 247 |
| 248 void testEvent(Stream stream, String type, [createEvent(String type)]) { |
| 249 var firedOnEvent = false; |
| 250 stream.listen((e) { |
| 251 firedOnEvent = true; |
| 252 }); |
| 253 expect(firedOnEvent, isFalse); |
| 254 var event = createEvent != null ? createEvent(type) : new Event(type); |
| 255 target.dispatchEvent(event); |
| 256 |
| 257 expect(firedOnEvent, isTrue); |
| 258 } |
| 259 |
| 260 testEvent(target.onAbort, 'abort'); |
| 261 testEvent(target.onBeforeCopy, 'beforecopy'); |
| 262 testEvent(target.onBeforeCut, 'beforecut'); |
| 263 testEvent(target.onBeforePaste, 'beforepaste'); |
| 264 testEvent(target.onBlur, 'blur'); |
| 265 testEvent(target.onChange, 'change'); |
| 266 testEvent( |
| 267 target.onContextMenu, 'contextmenu', (type) => new MouseEvent(type)); |
| 268 // We cannot test dispatching a true ClipboardEvent as the DOM does not |
| 269 // provide a way to create a fake ClipboardEvent. |
| 270 testEvent(target.onCopy, 'copy'); |
| 271 testEvent(target.onCut, 'cut'); |
| 272 testEvent(target.onPaste, 'paste'); |
| 273 |
| 274 testEvent( |
| 275 target.onDoubleClick, 'dblclick', (type) => new MouseEvent(type)); |
| 276 testEvent(target.onDrag, 'drag', (type) => new MouseEvent(type)); |
| 277 testEvent(target.onDragEnd, 'dragend', (type) => new MouseEvent(type)); |
| 278 testEvent( |
| 279 target.onDragEnter, 'dragenter', (type) => new MouseEvent(type)); |
| 280 testEvent( |
| 281 target.onDragLeave, 'dragleave', (type) => new MouseEvent(type)); |
| 282 testEvent(target.onDragOver, 'dragover', (type) => new MouseEvent(type)); |
| 283 testEvent( |
| 284 target.onDragStart, 'dragstart', (type) => new MouseEvent(type)); |
| 285 testEvent(target.onDrop, 'drop', (type) => new MouseEvent(type)); |
| 286 testEvent(target.onError, 'error'); |
| 287 testEvent(target.onFocus, 'focus'); |
| 288 testEvent(target.onFullscreenChange, 'webkitfullscreenchange'); |
| 289 testEvent(target.onInput, 'input'); |
| 290 testEvent(target.onInvalid, 'invalid'); |
| 291 testEvent(target.onKeyDown, 'keydown', (type) => new KeyboardEvent(type)); |
| 292 testEvent( |
| 293 target.onKeyPress, 'keypress', (type) => new KeyboardEvent(type)); |
| 294 testEvent(target.onKeyUp, 'keyup', (type) => new KeyboardEvent(type)); |
| 295 testEvent(target.onLoad, 'load'); |
| 296 testEvent( |
| 297 target.onMouseDown, 'mousedown', (type) => new MouseEvent(type)); |
| 298 testEvent( |
| 299 target.onMouseMove, 'mousemove', (type) => new MouseEvent(type)); |
| 300 testEvent(target.onMouseOut, 'mouseout', (type) => new MouseEvent(type)); |
| 301 testEvent( |
| 302 target.onMouseOver, 'mouseover', (type) => new MouseEvent(type)); |
| 303 testEvent(target.onMouseUp, 'mouseup', (type) => new MouseEvent(type)); |
| 304 testEvent(target.onReset, 'reset'); |
| 305 testEvent(target.onScroll, 'scroll'); |
| 306 testEvent(target.onSearch, 'search'); |
| 307 testEvent(target.onSelect, 'select'); |
| 308 testEvent(target.onSelectStart, 'selectstart'); |
| 309 testEvent(target.onSubmit, 'submit'); |
| 310 // We would prefer to create new touch events for this test via |
| 311 // new TouchEvent(null, null, null, type) |
| 312 // but that fails on desktop browsers as touch is not enabled. |
| 313 testEvent(target.onTouchCancel, 'touchcancel'); |
| 314 testEvent(target.onTouchEnd, 'touchend'); |
| 315 testEvent(target.onTouchLeave, 'touchleave'); |
| 316 testEvent(target.onTouchMove, 'touchmove'); |
| 317 testEvent(target.onTouchStart, 'touchstart'); |
| 318 }); |
| 319 }); |
| 320 |
| 321 group('click', () { |
| 322 test('clickEvent', () { |
| 323 var e = new DivElement(); |
| 324 var firedEvent = false; |
| 325 e.onClick.listen((event) { |
| 326 firedEvent = true; |
| 327 }); |
| 328 expect(firedEvent, false); |
| 329 e.click(); |
| 330 expect(firedEvent, true); |
| 331 |
| 332 var e2 = new DivElement(); |
| 333 var firedEvent2 = false; |
| 334 e2.onClick.matches('.foo').listen((event) { |
| 335 firedEvent2 = true; |
| 336 }); |
| 337 e2.click(); |
| 338 expect(firedEvent2, false); |
| 339 e2.classes.add('foo'); |
| 340 e2.click(); |
| 341 expect(firedEvent2, true); |
| 342 }); |
| 343 }); |
| 344 |
| 345 group('attributes', () { |
| 346 test('manipulation', () { |
| 347 final element = new Element.html( |
| 348 '''<div class="foo" style="overflow: hidden" data-foo="bar" |
| 349 data-foo2="bar2" dir="rtl"> |
| 350 </div>''', |
| 351 treeSanitizer: new NullTreeSanitizer()); |
| 352 final attributes = element.attributes; |
| 353 expect(attributes['class'], 'foo'); |
| 354 expect(attributes['style'], startsWith('overflow: hidden')); |
| 355 expect(attributes['data-foo'], 'bar'); |
| 356 expect(attributes['data-foo2'], 'bar2'); |
| 357 expect(attributes.length, 5); |
| 358 expect(element.dataset.length, 2); |
| 359 element.dataset['foo'] = 'baz'; |
| 360 expect(element.dataset['foo'], 'baz'); |
| 361 expect(attributes['data-foo'], 'baz'); |
| 362 attributes['data-foo2'] = 'baz2'; |
| 363 expect(attributes['data-foo2'], 'baz2'); |
| 364 expect(element.dataset['foo2'], 'baz2'); |
| 365 expect(attributes['dir'], 'rtl'); |
| 366 |
| 367 final dataset = element.dataset; |
| 368 dataset.remove('foo2'); |
| 369 expect(attributes.length, 4); |
| 370 expect(dataset.length, 1); |
| 371 attributes.remove('style'); |
| 372 expect(attributes.length, 3); |
| 373 dataset['foo3'] = 'baz3'; |
| 374 expect(dataset.length, 2); |
| 375 expect(attributes.length, 4); |
| 376 attributes['style'] = 'width: 300px;'; |
| 377 expect(attributes.length, 5); |
| 378 }); |
| 379 |
| 380 test('namespaces', () { |
| 381 var element = |
| 382 new svg.SvgElement.svg('''<svg xmlns="http://www.w3.org/2000/svg" |
| 383 xmlns:xlink="http://www.w3.org/1999/xlink"> |
| 384 <image xlink:href="foo" data-foo="bar"/> |
| 385 </svg>''').children[0]; |
| 386 |
| 387 var attributes = element.attributes; |
| 388 expect(attributes.length, 1); |
| 389 expect(attributes['data-foo'], 'bar'); |
| 390 |
| 391 var xlinkAttrs = |
| 392 element.getNamespacedAttributes('http://www.w3.org/1999/xlink'); |
| 393 expect(xlinkAttrs.length, 1); |
| 394 expect(xlinkAttrs['href'], 'foo'); |
| 395 |
| 396 xlinkAttrs.remove('href'); |
| 397 expect(xlinkAttrs.length, 0); |
| 398 |
| 399 xlinkAttrs['href'] = 'bar'; |
| 400 expect(xlinkAttrs['href'], 'bar'); |
| 401 |
| 402 var randomAttrs = element.getNamespacedAttributes('http://example.com'); |
| 403 expect(randomAttrs.length, 0); |
| 404 randomAttrs['href'] = 'bar'; |
| 405 expect(randomAttrs.length, 1); |
| 406 }); |
| 407 }); |
| 408 |
| 409 group('children', () { |
| 410 test('is a subset of nodes', () { |
| 411 var el = new Element.html("<div>Foo<br/><img/></div>"); |
| 412 expect(el.nodes.length, 3); |
| 413 expect(el.children.length, 2); |
| 414 expect(el.nodes[1], el.children[0]); |
| 415 expect(el.nodes[2], el.children[1]); |
| 416 }); |
| 417 |
| 418 test('changes when an element is added to nodes', () { |
| 419 var el = new Element.html("<div>Foo<br/><img/></div>"); |
| 420 el.nodes.add(new Element.tag('hr')); |
| 421 expect(el.children.length, 3); |
| 422 expect(el.children[2], isHRElement); |
| 423 expect(el.nodes[3], el.children[2]); |
| 424 }); |
| 425 |
| 426 test('changes nodes when an element is added', () { |
| 427 var el = new Element.html("<div>Foo<br/><img/></div>"); |
| 428 el.children.add(new Element.tag('hr')); |
| 429 expect(el.nodes.length, 4); |
| 430 expect(el.nodes[3], isHRElement); |
| 431 expect(el.children[2], el.nodes[3]); |
| 432 }); |
| 433 |
| 434 test('last', () { |
| 435 var el = makeElementWithChildren(); |
| 436 expect(el.children.last, isInputElement); |
| 437 }); |
| 438 |
| 439 test('forEach', () { |
| 440 var els = []; |
| 441 var el = makeElementWithChildren(); |
| 442 el.children.forEach((n) => els.add(n)); |
| 443 expect(els[0], isBRElement); |
| 444 expect(els[1], isImageElement); |
| 445 expect(els[2], isInputElement); |
| 446 }); |
| 447 |
| 448 test('where', () { |
| 449 var filtered = |
| 450 makeElementWithChildren().children.where((n) => n is ImageElement); |
| 451 expect(1, filtered.length); |
| 452 expect(filtered.first, isImageElement); |
| 453 expect(filtered, isElementIterable); |
| 454 }); |
| 455 |
| 456 test('every', () { |
| 457 var el = makeElementWithChildren(); |
| 458 expect(el.children.every((n) => n is Element), isTrue); |
| 459 expect(el.children.every((n) => n is InputElement), isFalse); |
| 460 }); |
| 461 |
| 462 test('any', () { |
| 463 var el = makeElementWithChildren(); |
| 464 expect(el.children.any((n) => n is InputElement), isTrue); |
| 465 expect(el.children.any((n) => n is svg.SvgElement), isFalse); |
| 466 }); |
| 467 |
| 468 test('isEmpty', () { |
| 469 expect(makeElement().children.isEmpty, isTrue); |
| 470 expect(makeElementWithChildren().children.isEmpty, isFalse); |
| 471 }); |
| 472 |
| 473 test('length', () { |
| 474 expect(makeElement().children.length, 0); |
| 475 expect(makeElementWithChildren().children.length, 3); |
| 476 }); |
| 477 |
| 478 test('[]', () { |
| 479 var el = makeElementWithChildren(); |
| 480 expect(el.children[0], isBRElement); |
| 481 expect(el.children[1], isImageElement); |
| 482 expect(el.children[2], isInputElement); |
| 483 }); |
| 484 |
| 485 test('[]=', () { |
| 486 var el = makeElementWithChildren(); |
| 487 el.children[1] = new Element.tag('hr'); |
| 488 expect(el.children[0], isBRElement); |
| 489 expect(el.children[1], isHRElement); |
| 490 expect(el.children[2], isInputElement); |
| 491 }); |
| 492 |
| 493 test('add', () { |
| 494 var el = makeElement(); |
| 495 el.children.add(new Element.tag('hr')); |
| 496 expect(el.children.last, isHRElement); |
| 497 }); |
| 498 |
| 499 test('iterator', () { |
| 500 var els = []; |
| 501 var el = makeElementWithChildren(); |
| 502 for (var subel in el.children) { |
| 503 els.add(subel); |
| 504 } |
| 505 expect(els[0], isBRElement); |
| 506 expect(els[1], isImageElement); |
| 507 expect(els[2], isInputElement); |
| 508 }); |
| 509 |
| 510 test('addAll', () { |
| 511 var el = makeElementWithChildren(); |
| 512 el.children.addAll([ |
| 513 new Element.tag('span'), |
| 514 new Element.tag('a'), |
| 515 new Element.tag('h1') |
| 516 ]); |
| 517 expect(el.children[0], isBRElement); |
| 518 expect(el.children[1], isImageElement); |
| 519 expect(el.children[2], isInputElement); |
| 520 expect(el.children[3], isSpanElement); |
| 521 expect(el.children[4], isAnchorElement); |
| 522 expect(el.children[5], isHeadingElement); |
| 523 }); |
| 524 |
| 525 test('insert', () { |
| 526 var element = new DivElement(); |
| 527 element.children.insert(0, new BRElement()); |
| 528 expect(element.children[0], isBRElement); |
| 529 element.children.insert(0, new HRElement()); |
| 530 expect(element.children[0], isHRElement); |
| 531 element.children.insert(1, new ImageElement()); |
| 532 expect(element.children[1], isImageElement); |
| 533 element.children.insert(element.children.length, new InputElement()); |
| 534 expect(element.children.last, isInputElement); |
| 535 }); |
| 536 |
| 537 test('clear', () { |
| 538 var el = makeElementWithChildren(); |
| 539 el.children.clear(); |
| 540 expect(el.children, equals([])); |
| 541 }); |
| 542 |
| 543 test('removeLast', () { |
| 544 var el = makeElementWithChildren(); |
| 545 expect(el.children.removeLast(), isInputElement); |
| 546 expect(el.children.length, 2); |
| 547 expect(el.children.removeLast(), isImageElement); |
| 548 expect(el.children.length, 1); |
| 549 }); |
| 550 |
| 551 test('sublist', () { |
| 552 var el = makeElementWithChildren(); |
| 553 expect(el.children.sublist(1, 2), isElementList); |
| 554 }); |
| 555 |
| 556 test('getRange', () { |
| 557 var el = makeElementWithChildren(); |
| 558 expect(el.children.getRange(1, 2).length, 1); |
| 559 }); |
| 560 |
| 561 test('retainWhere', () { |
| 562 var el = makeElementWithChildren(); |
| 563 expect(el.children.length, 3); |
| 564 el.children.retainWhere((e) => true); |
| 565 expect(el.children.length, 3); |
| 566 |
| 567 el = makeElementWithChildren(); |
| 568 expect(el.children.length, 3); |
| 569 el.children.retainWhere((e) => false); |
| 570 expect(el.children.length, 0); |
| 571 |
| 572 el = makeElementWithChildren(); |
| 573 expect(el.children.length, 3); |
| 574 el.children.retainWhere((e) => e.localName == 'input'); |
| 575 expect(el.children.length, 1); |
| 576 |
| 577 el = makeElementWithChildren(); |
| 578 expect(el.children.length, 3); |
| 579 el.children.retainWhere((e) => e.localName == 'br'); |
| 580 expect(el.children.length, 1); |
| 581 }); |
| 582 |
| 583 test('removeWhere', () { |
| 584 var el = makeElementWithChildren(); |
| 585 expect(el.children.length, 3); |
| 586 el.children.removeWhere((e) => true); |
| 587 expect(el.children.length, 0); |
| 588 |
| 589 el = makeElementWithChildren(); |
| 590 expect(el.children.length, 3); |
| 591 el.children.removeWhere((e) => false); |
| 592 expect(el.children.length, 3); |
| 593 |
| 594 el = makeElementWithChildren(); |
| 595 expect(el.children.length, 3); |
| 596 el.children.removeWhere((e) => e.localName == 'input'); |
| 597 expect(el.children.length, 2); |
| 598 |
| 599 el = makeElementWithChildren(); |
| 600 expect(el.children.length, 3); |
| 601 el.children.removeWhere((e) => e.localName == 'br'); |
| 602 expect(el.children.length, 2); |
| 603 }); |
| 604 |
| 605 testUnsupported('sort', () { |
| 606 var l = makeElementWithChildren().children; |
| 607 l.sort(); |
| 608 }); |
| 609 |
| 610 testUnsupported('setRange', () { |
| 611 var l = makeElementWithChildren().children; |
| 612 l.setRange(0, 0, []); |
| 613 }); |
| 614 |
| 615 testUnsupported('replaceRange', () { |
| 616 var l = makeElementWithChildren().children; |
| 617 l.replaceRange(0, 0, []); |
| 618 }); |
| 619 |
| 620 testUnsupported('removeRange', () { |
| 621 var l = makeElementWithChildren().children; |
| 622 l.removeRange(0, 1); |
| 623 }); |
| 624 |
| 625 testUnsupported('insertAll', () { |
| 626 var l = makeElementWithChildren().children; |
| 627 l.insertAll(0, []); |
| 628 }); |
| 629 }); |
| 630 |
| 631 group('matches', () { |
| 632 test('matches', () { |
| 633 var element = new DivElement(); |
| 634 document.body.append(element); |
| 635 element.classes.add('test'); |
| 636 |
| 637 expect(element.matches('div'), true); |
| 638 expect(element.matches('span'), false); |
| 639 expect(element.matches('.test'), true); |
| 640 }); |
| 641 }); |
| 642 |
| 643 group('queryAll', () { |
| 644 List<Element> getQueryAll() { |
| 645 return new Element.html(""" |
| 646 <div> |
| 647 <hr/> |
| 648 <a class='q' href='http://dartlang.org'>Dart!</a> |
| 649 <p> |
| 650 <span class='q'>Hello</span>, |
| 651 <em>world</em>! |
| 652 </p> |
| 653 <hr class='q'/> |
| 654 </div> |
| 655 """).queryAll('.q'); |
| 656 } |
| 657 |
| 658 List<Element> getEmptyQueryAll() => new Element.tag('div').queryAll('img'); |
| 659 |
| 660 test('last', () { |
| 661 expect(getQueryAll().last, isHRElement); |
| 662 }); |
| 663 |
| 664 test('forEach', () { |
| 665 var els = []; |
| 666 getQueryAll().forEach((el) => els.add(el)); |
| 667 expect(els[0], isAnchorElement); |
| 668 expect(els[1], isSpanElement); |
| 669 expect(els[2], isHRElement); |
| 670 }); |
| 671 |
| 672 test('map', () { |
| 673 var texts = getQueryAll().map((el) => el.text).toList(); |
| 674 expect(texts, equals(['Dart!', 'Hello', ''])); |
| 675 }); |
| 676 |
| 677 test('where', () { |
| 678 var filtered = getQueryAll().where((n) => n is SpanElement).toList(); |
| 679 expect(filtered.length, 1); |
| 680 expect(filtered[0], isSpanElement); |
| 681 expect(filtered, isElementList); |
| 682 }); |
| 683 |
| 684 test('every', () { |
| 685 var el = getQueryAll(); |
| 686 expect(el.every((n) => n is Element), isTrue); |
| 687 expect(el.every((n) => n is SpanElement), isFalse); |
| 688 }); |
| 689 |
| 690 test('any', () { |
| 691 var el = getQueryAll(); |
| 692 expect(el.any((n) => n is SpanElement), isTrue); |
| 693 expect(el.any((n) => n is svg.SvgElement), isFalse); |
| 694 }); |
| 695 |
| 696 test('isEmpty', () { |
| 697 expect(getEmptyQueryAll().isEmpty, isTrue); |
| 698 expect(getQueryAll().isEmpty, isFalse); |
| 699 }); |
| 700 |
| 701 test('length', () { |
| 702 expect(getEmptyQueryAll().length, 0); |
| 703 expect(getQueryAll().length, 3); |
| 704 }); |
| 705 |
| 706 test('[]', () { |
| 707 var els = getQueryAll(); |
| 708 expect(els[0], isAnchorElement); |
| 709 expect(els[1], isSpanElement); |
| 710 expect(els[2], isHRElement); |
| 711 }); |
| 712 |
| 713 test('iterator', () { |
| 714 var els = []; |
| 715 for (var subel in getQueryAll()) { |
| 716 els.add(subel); |
| 717 } |
| 718 expect(els[0], isAnchorElement); |
| 719 expect(els[1], isSpanElement); |
| 720 expect(els[2], isHRElement); |
| 721 }); |
| 722 |
| 723 test('sublist', () { |
| 724 expect(getQueryAll().sublist(1, 2) is List<Element>, isTrue); |
| 725 }); |
| 726 |
| 727 testUnsupported('[]=', () => getQueryAll()[1] = new Element.tag('br')); |
| 728 testUnsupported('add', () => getQueryAll().add(new Element.tag('br'))); |
| 729 |
| 730 testUnsupported('addAll', () { |
| 731 getQueryAll().addAll([ |
| 732 new Element.tag('span'), |
| 733 new Element.tag('a'), |
| 734 new Element.tag('h1') |
| 735 ]); |
| 736 }); |
| 737 |
| 738 testUnsupported('sort', () => getQueryAll().sort((a1, a2) => true)); |
| 739 |
| 740 testUnsupported('setRange', () { |
| 741 getQueryAll().setRange(0, 1, [new BRElement()]); |
| 742 }); |
| 743 |
| 744 testUnsupported('removeRange', () => getQueryAll().removeRange(0, 1)); |
| 745 |
| 746 testUnsupported('clear', () => getQueryAll().clear()); |
| 747 |
| 748 testUnsupported('removeLast', () => getQueryAll().removeLast()); |
| 749 }); |
| 750 |
| 751 group('functional', () { |
| 752 test('toString', () { |
| 753 final elems = makeElementWithChildren().children; |
| 754 expect(elems.toString(), "[br, img, input]"); |
| 755 final elem = makeElement().children; |
| 756 expect(elem.toString(), '[]'); |
| 757 }); |
| 758 |
| 759 test('scrollIntoView', () { |
| 760 var child = new DivElement(); |
| 761 document.body.append(child); |
| 762 |
| 763 child.scrollIntoView(ScrollAlignment.TOP); |
| 764 child.scrollIntoView(ScrollAlignment.BOTTOM); |
| 765 child.scrollIntoView(ScrollAlignment.CENTER); |
| 766 child.scrollIntoView(); |
| 767 }); |
| 768 }); |
| 769 |
| 770 group('_ElementList', () { |
| 771 List<Element> makeElList() => makeElementWithChildren().children; |
| 772 |
| 773 test('where', () { |
| 774 var filtered = makeElList().where((n) => n is ImageElement); |
| 775 expect(filtered.length, 1); |
| 776 expect(filtered.first, isImageElement); |
| 777 expect(filtered, isElementIterable); |
| 778 }); |
| 779 |
| 780 test('sublist', () { |
| 781 var range = makeElList().sublist(1, 3); |
| 782 expect(range, isElementList); |
| 783 expect(range[0], isImageElement); |
| 784 expect(range[1], isInputElement); |
| 785 }); |
| 786 }); |
| 787 |
| 788 group('eventDelegation', () { |
| 789 test('matches', () { |
| 790 Element clickOne = new Element.a(); |
| 791 Element selectorOne = new Element.div() |
| 792 ..classes.add('selector') |
| 793 ..children.add(clickOne); |
| 794 |
| 795 Element clickTwo = new Element.a(); |
| 796 Element selectorTwo = new Element.div() |
| 797 ..classes.add('selector') |
| 798 ..children.add(clickTwo); |
| 799 document.body.append(selectorOne); |
| 800 document.body.append(selectorTwo); |
| 801 |
| 802 document.body.onClick |
| 803 .matches('.selector') |
| 804 .listen(expectAsync((Event event) { |
| 805 expect(event.currentTarget, document.body); |
| 806 expect(event.target, clickOne); |
| 807 expect(event.matchingTarget, selectorOne); |
| 808 })); |
| 809 |
| 810 selectorOne.onClick |
| 811 .matches('.selector') |
| 812 .listen(expectAsync((Event event) { |
| 813 expect(event.currentTarget, selectorOne); |
| 814 expect(event.target, clickOne); |
| 815 expect(event.matchingTarget, selectorOne); |
| 816 })); |
| 817 clickOne.click(); |
| 818 |
| 819 Element elem = new Element.div()..classes.addAll(['a', 'b']); |
| 820 Element img = new Element.img() |
| 821 ..classes.addAll(['b', 'a', 'd']) |
| 822 ..id = 'cookie'; |
| 823 Element input = new InputElement()..classes.addAll(['c', 'd']); |
| 824 var div = new Element.div() |
| 825 ..classes.add('a') |
| 826 ..id = 'wat'; |
| 827 document.body.append(elem); |
| 828 document.body.append(img); |
| 829 document.body.append(input); |
| 830 document.body.append(div); |
| 831 |
| 832 Element elem4 = new Element.div()..classes.addAll(['i', 'j']); |
| 833 Element elem5 = new Element.div() |
| 834 ..classes.addAll(['g', 'h']) |
| 835 ..children.add(elem4); |
| 836 Element elem6 = new Element.div() |
| 837 ..classes.addAll(['e', 'f']) |
| 838 ..children.add(elem5); |
| 839 document.body.append(elem6); |
| 840 |
| 841 var firedEvent = false; |
| 842 var elems = queryAll('.a'); |
| 843 queryAll('.a').onClick.listen((event) { |
| 844 firedEvent = true; |
| 845 }); |
| 846 expect(firedEvent, false); |
| 847 query('.c').click(); |
| 848 expect(firedEvent, false); |
| 849 query('#wat').click(); |
| 850 expect(firedEvent, true); |
| 851 |
| 852 var firedEvent4 = false; |
| 853 queryAll('.a').onClick.matches('.d').listen((event) { |
| 854 firedEvent4 = true; |
| 855 }); |
| 856 expect(firedEvent4, false); |
| 857 query('.c').click(); |
| 858 expect(firedEvent4, false); |
| 859 query('#wat').click(); |
| 860 expect(firedEvent4, false); |
| 861 query('#cookie').click(); |
| 862 expect(firedEvent4, true); |
| 863 |
| 864 var firedEvent2 = false; |
| 865 queryAll('.a').onClick.listen((event) { |
| 866 firedEvent2 = true; |
| 867 }); |
| 868 Element elem2 = new Element.html('<div class="a"><br/>'); |
| 869 document.body.append(elem2); |
| 870 elem2.click(); |
| 871 expect(firedEvent2, false); |
| 872 elem2.classes.add('a'); |
| 873 elem2.click(); |
| 874 expect(firedEvent2, false); |
| 875 |
| 876 var firedEvent3 = false; |
| 877 queryAll(':root').onClick.matches('.a').listen((event) { |
| 878 firedEvent3 = true; |
| 879 }); |
| 880 Element elem3 = new Element.html('<div class="d"><br/>'); |
| 881 document.body.append(elem3); |
| 882 elem3.click(); |
| 883 expect(firedEvent3, false); |
| 884 elem3.classes.add('a'); |
| 885 elem3.click(); |
| 886 expect(firedEvent3, true); |
| 887 |
| 888 var firedEvent5 = false; |
| 889 queryAll(':root').onClick.matches('.e').listen((event) { |
| 890 firedEvent5 = true; |
| 891 }); |
| 892 expect(firedEvent5, false); |
| 893 query('.i').click(); |
| 894 expect(firedEvent5, true); |
| 895 }); |
| 896 |
| 897 test('event ordering', () { |
| 898 var a = new DivElement(); |
| 899 var b = new DivElement(); |
| 900 a.append(b); |
| 901 var c = new DivElement(); |
| 902 b.append(c); |
| 903 |
| 904 var eventOrder = []; |
| 905 |
| 906 a.on['custom_event'].listen((_) { |
| 907 eventOrder.add('a no-capture'); |
| 908 }); |
| 909 |
| 910 a.on['custom_event'].capture((_) { |
| 911 eventOrder.add('a capture'); |
| 912 }); |
| 913 |
| 914 b.on['custom_event'].listen((_) { |
| 915 eventOrder.add('b no-capture'); |
| 916 }); |
| 917 |
| 918 b.on['custom_event'].capture((_) { |
| 919 eventOrder.add('b capture'); |
| 920 }); |
| 921 |
| 922 document.body.append(a); |
| 923 |
| 924 var event = new Event('custom_event', canBubble: true); |
| 925 c.dispatchEvent(event); |
| 926 expect(eventOrder, |
| 927 ['a capture', 'b capture', 'b no-capture', 'a no-capture']); |
| 928 }); |
| 929 }); |
| 930 |
| 931 group('ElementList', () { |
| 932 // Tests for methods on the DOM class 'NodeList'. |
| 933 // |
| 934 // There are two interesting things that are checked here from the viewpoint |
| 935 // of the dart2js implementation of a 'native' class: |
| 936 // |
| 937 // 1. Some methods are implementated from by 'Object' or 'Interceptor'; |
| 938 // some of these tests simply check that a method can be called. |
| 939 // 2. Some methods are implemented by mixins. |
| 940 |
| 941 ElementList<Element> makeElementList() => |
| 942 (new Element.html("<div>Foo<br/><!--baz--><br/><br/></div>")) |
| 943 .queryAll('br'); |
| 944 |
| 945 test('hashCode', () { |
| 946 var nodes = makeElementList(); |
| 947 var hash = nodes.hashCode; |
| 948 final int N = 1000; |
| 949 int matchCount = 0; |
| 950 for (int i = 0; i < N; i++) { |
| 951 if (makeElementList().hashCode == hash) matchCount++; |
| 952 } |
| 953 expect(matchCount, lessThan(N)); |
| 954 }); |
| 955 |
| 956 test('operator==', () { |
| 957 var a = [makeElementList(), makeElementList(), null]; |
| 958 for (int i = 0; i < a.length; i++) { |
| 959 for (int j = 0; j < a.length; j++) { |
| 960 expect(i == j, a[i] == a[j]); |
| 961 } |
| 962 } |
| 963 }); |
| 964 |
| 965 test('runtimeType', () { |
| 966 var nodes1 = makeElementList(); |
| 967 var nodes2 = makeElementList(); |
| 968 var type1 = nodes1.runtimeType; |
| 969 var type2 = nodes2.runtimeType; |
| 970 expect(type1 == type2, true); |
| 971 String name = '$type1'; |
| 972 if (name.length > 3) { |
| 973 expect(name.contains('ElementList'), true); |
| 974 } |
| 975 }); |
| 976 |
| 977 test('first', () { |
| 978 var nodes = makeElementList(); |
| 979 expect(nodes.first, isBRElement); |
| 980 }); |
| 981 |
| 982 test('last', () { |
| 983 var nodes = makeElementList(); |
| 984 expect(nodes.last, isBRElement); |
| 985 }); |
| 986 |
| 987 test('where', () { |
| 988 var filtered = makeElementList().where((n) => n is BRElement).toList(); |
| 989 expect(filtered.length, 3); |
| 990 expect(filtered[0], isBRElement); |
| 991 }); |
| 992 |
| 993 test('sublist', () { |
| 994 var range = makeElementList().sublist(1, 3); |
| 995 expect(range.length, 2); |
| 996 expect(range[0], isBRElement); |
| 997 expect(range[1], isBRElement); |
| 998 }); |
| 999 }); |
| 1000 } |
OLD | NEW |