blob: 4e658273505640cb2fc4ca44b58ef187ae4b8eb7 [file] [log] [blame]
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
library ElementTest;
import 'package:async_helper/async_minitest.dart';
import 'package:expect/expect.dart';
import 'dart:async';
import 'dart:html';
import 'dart:svg' as svg;
import 'utils.dart';
expectLargeRect(Rectangle rect) {
expect(rect.top, 0);
expect(rect.left, 0);
expect(rect.width, greaterThan(100));
expect(rect.height, greaterThan(100));
expect(rect.bottom, rect.top + rect.height);
expect(rect.right, rect.left + rect.width);
}
void testUnsupported(String name, void f()) {
test(name, () => Expect.throwsUnsupportedError(f));
}
main() {
var isHRElement = predicate((x) => x is HRElement, 'is a HRElement');
var isBRElement = predicate((x) => x is BRElement, 'is a BRElement');
var isInputElement =
predicate((x) => x is InputElement, 'is an InputElement');
var isImageElement =
predicate((x) => x is ImageElement, 'is an ImageElement');
var isSpanElement = predicate((x) => x is SpanElement, 'is a SpanElement');
var isAnchorElement =
predicate((x) => x is AnchorElement, 'is an AnchorElement');
var isElementList =
predicate((x) => x is List<Element>, 'is a List<Element>');
var isElementIterable =
predicate((x) => x is Iterable<Element>, 'is an Iterable<Element>');
var isHeadingElement =
predicate((x) => x is HeadingElement, 'is a HeadingElement');
Element makeElement() => new Element.tag('div');
Element makeElementWithChildren() =>
new Element.html("<div><br/><img/><input/></div>");
group('position', () {
test('computedStyle', () {
final element = document.body;
var style = element.getComputedStyle();
expect(style.getPropertyValue('left'), 'auto');
});
test('client position synchronous', () {
final container = new Element.tag("div");
container.style.position = 'absolute';
container.style.top = '8px';
container.style.left = '9px';
final element = new Element.tag("div");
element.style.width = '200px';
element.style.height = '200px';
container.children.add(element);
document.body.children.add(container);
expect(element.client.width, greaterThan(100));
expect(element.client.height, greaterThan(100));
expect(element.offset.width, greaterThan(100));
expect(element.offset.height, greaterThan(100));
expect(element.scrollWidth, greaterThan(100));
expect(element.scrollHeight, greaterThan(100));
expect(element.getBoundingClientRect().left, 9);
expect(element.getBoundingClientRect().top, 8);
expect(element.documentOffset.x, 9);
expect(element.documentOffset.y, 8);
container.remove();
});
});
group('constructors', () {
test('error', () {
Expect.throwsStateError(() => new Element.html('<br/><br/>'));
});
test('.html has no parent',
() => expect(new Element.html('<br/>').parent, isNull));
test('.html table', () {
// http://developers.whatwg.org/tabular-data.html#tabular-data
TableElement node = new Element.html('''
<table>
<caption>Characteristics with positive and negative sides</caption>
<thead>
<tr>
<th id="n"> Negative
<th> Characteristic
<th> Positive
<tbody>
<tr>
<td headers="n r1"> Sad
<th id="r1"> Mood
<td> Happy
<tr>
<td headers="n r2"> Failing
<th id="r2"> Grade
<td> Passing
</table>''');
expect(node, predicate((x) => x is TableElement, 'is a TableElement'));
expect(node.tagName, 'TABLE');
expect(node.parent, isNull);
expect(node.caption.innerHtml,
'Characteristics with positive and negative sides');
expect(node.tHead.rows.length, 1);
expect(node.tHead.rows[0].cells.length, 3);
expect(node.tBodies.length, 1);
expect(node.tBodies[0].rows.length, 2);
expect(node.tBodies[0].rows[1].cells.map((c) => c.innerHtml),
[' Failing\n ', ' Grade\n ', ' Passing\n']);
});
test('.html caption', () {
var table = new TableElement();
TableCaptionElement node =
table.createFragment('<caption><p>Table 1.').nodes.single;
expect(
node,
predicate(
(x) => x is TableCaptionElement, 'is a TableCaptionElement'));
expect(node.tagName, 'CAPTION');
expect(node.parent, isNull);
expect(node.innerHtml, '<p>Table 1.</p>');
});
test('.html colgroup', () {
var table = new TableElement();
TableColElement node =
table.createFragment('<colgroup> <col> <col> <col>').nodes.single;
expect(
node, predicate((x) => x is TableColElement, 'is a TableColElement'));
expect(node.tagName, 'COLGROUP');
expect(node.parent, isNull);
expect(node.innerHtml, ' <col> <col> <col>');
});
test('.html tbody', () {
var innerHtml = '<tr><td headers="n r1">Sad</td><td>Happy</td></tr>';
var table = new TableElement();
TableSectionElement node =
table.createFragment('<tbody>$innerHtml').nodes.single;
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TBODY');
expect(node.parent, isNull);
expect(node.rows.length, 1);
expect(node.rows[0].cells.length, 2);
expect(node.innerHtml, innerHtml);
});
test('.html thead', () {
var innerHtml = '<tr><th id="n">Negative</th><th>Positive</th></tr>';
var table = new TableElement();
TableSectionElement node =
table.createFragment('<thead>$innerHtml').nodes.single;
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'THEAD');
expect(node.parent, isNull);
expect(node.rows.length, 1);
expect(node.rows[0].cells.length, 2);
expect(node.innerHtml, innerHtml);
});
test('.html tfoot', () {
var innerHtml = '<tr><th>percentage</th><td>34.3%</td></tr>';
var table = new TableElement();
TableSectionElement node =
table.createFragment('<tfoot>$innerHtml').nodes.single;
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TFOOT');
expect(node.parent, isNull);
expect(node.rows.length, 1);
expect(node.rows[0].cells.length, 2);
expect(node.innerHtml, innerHtml);
});
test('.html tr', () {
var table = new TableElement();
document.body.append(table);
var tBody = table.createTBody();
TableRowElement node =
tBody.createFragment('<tr><td>foo<td>bar').nodes.single;
expect(
node, predicate((x) => x is TableRowElement, 'is a TableRowElement'));
expect(node.tagName, 'TR');
expect(node.parent, isNull);
expect(node.cells.map((c) => c.innerHtml), ['foo', 'bar']);
});
test('.html td', () {
var table = new TableElement();
document.body.append(table);
var tBody = table.createTBody();
var tRow = tBody.addRow();
TableCellElement node = tRow.createFragment('<td>foobar').nodes.single;
expect(node,
predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TD');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
});
test('.html th', () {
var table = new TableElement();
document.body.append(table);
var tBody = table.createTBody();
var tRow = tBody.addRow();
TableCellElement node = tRow.createFragment('<th>foobar').nodes.single;
expect(node,
predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TH');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
});
test('.html can fire events', () {
var e = new Element.html('<button>aha</button>');
var gotEvent = false;
e.onClick.listen((_) {
gotEvent = true;
});
e.click();
expect(gotEvent, isTrue, reason: 'click should have raised click event');
});
});
group('eventListening', () {
test('streams', () {
final target = new TextAreaElement();
void testEvent(Stream stream, String type, [createEvent(String type)]) {
var firedOnEvent = false;
stream.listen((e) {
firedOnEvent = true;
});
expect(firedOnEvent, isFalse);
var event = createEvent != null ? createEvent(type) : new Event(type);
target.dispatchEvent(event);
expect(firedOnEvent, isTrue);
}
testEvent(target.onAbort, 'abort');
testEvent(target.onBeforeCopy, 'beforecopy');
testEvent(target.onBeforeCut, 'beforecut');
testEvent(target.onBeforePaste, 'beforepaste');
testEvent(target.onBlur, 'blur');
testEvent(target.onChange, 'change');
testEvent(
target.onContextMenu, 'contextmenu', (type) => new MouseEvent(type));
// We cannot test dispatching a true ClipboardEvent as the DOM does not
// provide a way to create a fake ClipboardEvent.
testEvent(target.onCopy, 'copy');
testEvent(target.onCut, 'cut');
testEvent(target.onPaste, 'paste');
testEvent(
target.onDoubleClick, 'dblclick', (type) => new MouseEvent(type));
testEvent(target.onDrag, 'drag', (type) => new MouseEvent(type));
testEvent(target.onDragEnd, 'dragend', (type) => new MouseEvent(type));
testEvent(
target.onDragEnter, 'dragenter', (type) => new MouseEvent(type));
testEvent(
target.onDragLeave, 'dragleave', (type) => new MouseEvent(type));
testEvent(target.onDragOver, 'dragover', (type) => new MouseEvent(type));
testEvent(
target.onDragStart, 'dragstart', (type) => new MouseEvent(type));
testEvent(target.onDrop, 'drop', (type) => new MouseEvent(type));
testEvent(target.onError, 'error');
testEvent(target.onFocus, 'focus');
testEvent(target.onFullscreenChange, 'webkitfullscreenchange');
testEvent(target.onInput, 'input');
testEvent(target.onInvalid, 'invalid');
testEvent(target.onKeyDown, 'keydown', (type) => new KeyboardEvent(type));
testEvent(
target.onKeyPress, 'keypress', (type) => new KeyboardEvent(type));
testEvent(target.onKeyUp, 'keyup', (type) => new KeyboardEvent(type));
testEvent(target.onLoad, 'load');
testEvent(
target.onMouseDown, 'mousedown', (type) => new MouseEvent(type));
testEvent(
target.onMouseMove, 'mousemove', (type) => new MouseEvent(type));
testEvent(target.onMouseOut, 'mouseout', (type) => new MouseEvent(type));
testEvent(
target.onMouseOver, 'mouseover', (type) => new MouseEvent(type));
testEvent(target.onMouseUp, 'mouseup', (type) => new MouseEvent(type));
testEvent(target.onReset, 'reset');
testEvent(target.onScroll, 'scroll');
testEvent(target.onSearch, 'search');
testEvent(target.onSelect, 'select');
testEvent(target.onSelectStart, 'selectstart');
testEvent(target.onSubmit, 'submit');
// We would prefer to create new touch events for this test via
// new TouchEvent(null, null, null, type)
// but that fails on desktop browsers as touch is not enabled.
testEvent(target.onTouchCancel, 'touchcancel');
testEvent(target.onTouchEnd, 'touchend');
testEvent(target.onTouchLeave, 'touchleave');
testEvent(target.onTouchMove, 'touchmove');
testEvent(target.onTouchStart, 'touchstart');
});
});
group('click', () {
test('clickEvent', () {
var e = new DivElement();
var firedEvent = false;
e.onClick.listen((event) {
firedEvent = true;
});
expect(firedEvent, false);
e.click();
expect(firedEvent, true);
var e2 = new DivElement();
var firedEvent2 = false;
e2.onClick.matches('.foo').listen((event) {
firedEvent2 = true;
});
e2.click();
expect(firedEvent2, false);
e2.classes.add('foo');
e2.click();
expect(firedEvent2, true);
});
});
group('attributes', () {
test('manipulation', () {
final element = new Element.html(
'''<div class="foo" style="overflow: hidden" data-foo="bar"
data-foo2="bar2" dir="rtl">
</div>''',
treeSanitizer: new NullTreeSanitizer());
final attributes = element.attributes;
expect(attributes['class'], 'foo');
startsWith(match) => predicate((x) => x is String && x.startsWith(match));
expect(attributes['style'], startsWith('overflow: hidden'));
expect(attributes['data-foo'], 'bar');
expect(attributes['data-foo2'], 'bar2');
expect(attributes.length, 5);
expect(element.dataset.length, 2);
element.dataset['foo'] = 'baz';
expect(element.dataset['foo'], 'baz');
expect(attributes['data-foo'], 'baz');
attributes['data-foo2'] = 'baz2';
expect(attributes['data-foo2'], 'baz2');
expect(element.dataset['foo2'], 'baz2');
expect(attributes['dir'], 'rtl');
final dataset = element.dataset;
dataset.remove('foo2');
expect(attributes.length, 4);
expect(dataset.length, 1);
attributes.remove('style');
expect(attributes.length, 3);
dataset['foo3'] = 'baz3';
expect(dataset.length, 2);
expect(attributes.length, 4);
attributes['style'] = 'width: 300px;';
expect(attributes.length, 5);
});
test('namespaces', () {
var element =
new svg.SvgElement.svg('''<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="foo" data-foo="bar"/>
</svg>''').children[0];
var attributes = element.attributes;
expect(attributes.length, 1);
expect(attributes['data-foo'], 'bar');
var xlinkAttrs =
element.getNamespacedAttributes('http://www.w3.org/1999/xlink');
expect(xlinkAttrs.length, 1);
expect(xlinkAttrs['href'], 'foo');
xlinkAttrs.remove('href');
expect(xlinkAttrs.length, 0);
xlinkAttrs['href'] = 'bar';
expect(xlinkAttrs['href'], 'bar');
var randomAttrs = element.getNamespacedAttributes('http://example.com');
expect(randomAttrs.length, 0);
randomAttrs['href'] = 'bar';
expect(randomAttrs.length, 1);
});
});
group('children', () {
test('is a subset of nodes', () {
var el = new Element.html("<div>Foo<br/><img/></div>");
expect(el.nodes.length, 3);
expect(el.children.length, 2);
expect(el.nodes[1], el.children[0]);
expect(el.nodes[2], el.children[1]);
});
test('changes when an element is added to nodes', () {
var el = new Element.html("<div>Foo<br/><img/></div>");
el.nodes.add(new Element.tag('hr'));
expect(el.children.length, 3);
expect(el.children[2], isHRElement);
expect(el.nodes[3], el.children[2]);
});
test('changes nodes when an element is added', () {
var el = new Element.html("<div>Foo<br/><img/></div>");
el.children.add(new Element.tag('hr'));
expect(el.nodes.length, 4);
expect(el.nodes[3], isHRElement);
expect(el.children[2], el.nodes[3]);
});
test('last', () {
var el = makeElementWithChildren();
expect(el.children.last, isInputElement);
});
test('forEach', () {
var els = [];
var el = makeElementWithChildren();
el.children.forEach((n) => els.add(n));
expect(els[0], isBRElement);
expect(els[1], isImageElement);
expect(els[2], isInputElement);
});
test('where', () {
var filtered =
makeElementWithChildren().children.where((n) => n is ImageElement);
expect(1, filtered.length);
expect(filtered.first, isImageElement);
expect(filtered, isElementIterable);
});
test('every', () {
var el = makeElementWithChildren();
expect(el.children.every((n) => n is Element), isTrue);
expect(el.children.every((n) => n is InputElement), isFalse);
});
test('any', () {
var el = makeElementWithChildren();
expect(el.children.any((n) => n is InputElement), isTrue);
expect(el.children.any((n) => n is svg.SvgElement), isFalse);
});
test('isEmpty', () {
expect(makeElement().children.isEmpty, isTrue);
expect(makeElementWithChildren().children.isEmpty, isFalse);
});
test('length', () {
expect(makeElement().children.length, 0);
expect(makeElementWithChildren().children.length, 3);
});
test('[]', () {
var el = makeElementWithChildren();
expect(el.children[0], isBRElement);
expect(el.children[1], isImageElement);
expect(el.children[2], isInputElement);
});
test('[]=', () {
var el = makeElementWithChildren();
el.children[1] = new Element.tag('hr');
expect(el.children[0], isBRElement);
expect(el.children[1], isHRElement);
expect(el.children[2], isInputElement);
});
test('add', () {
var el = makeElement();
el.children.add(new Element.tag('hr'));
expect(el.children.last, isHRElement);
});
test('iterator', () {
var els = [];
var el = makeElementWithChildren();
for (var subel in el.children) {
els.add(subel);
}
expect(els[0], isBRElement);
expect(els[1], isImageElement);
expect(els[2], isInputElement);
});
test('addAll', () {
var el = makeElementWithChildren();
el.children.addAll([
new Element.tag('span'),
new Element.tag('a'),
new Element.tag('h1')
]);
expect(el.children[0], isBRElement);
expect(el.children[1], isImageElement);
expect(el.children[2], isInputElement);
expect(el.children[3], isSpanElement);
expect(el.children[4], isAnchorElement);
expect(el.children[5], isHeadingElement);
});
test('insert', () {
var element = new DivElement();
element.children.insert(0, new BRElement());
expect(element.children[0], isBRElement);
element.children.insert(0, new HRElement());
expect(element.children[0], isHRElement);
element.children.insert(1, new ImageElement());
expect(element.children[1], isImageElement);
element.children.insert(element.children.length, new InputElement());
expect(element.children.last, isInputElement);
});
test('clear', () {
var el = makeElementWithChildren();
el.children.clear();
expect(el.children, equals([]));
});
test('removeLast', () {
var el = makeElementWithChildren();
expect(el.children.removeLast(), isInputElement);
expect(el.children.length, 2);
expect(el.children.removeLast(), isImageElement);
expect(el.children.length, 1);
});
test('sublist', () {
var el = makeElementWithChildren();
expect(el.children.sublist(1, 2), isElementList);
});
test('getRange', () {
var el = makeElementWithChildren();
expect(el.children.getRange(1, 2).length, 1);
});
test('retainWhere', () {
var el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.retainWhere((e) => true);
expect(el.children.length, 3);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.retainWhere((e) => false);
expect(el.children.length, 0);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.retainWhere((e) => e.localName == 'input');
expect(el.children.length, 1);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.retainWhere((e) => e.localName == 'br');
expect(el.children.length, 1);
});
test('removeWhere', () {
var el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.removeWhere((e) => true);
expect(el.children.length, 0);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.removeWhere((e) => false);
expect(el.children.length, 3);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.removeWhere((e) => e.localName == 'input');
expect(el.children.length, 2);
el = makeElementWithChildren();
expect(el.children.length, 3);
el.children.removeWhere((e) => e.localName == 'br');
expect(el.children.length, 2);
});
testUnsupported('sort', () {
var l = makeElementWithChildren().children;
l.sort();
});
testUnsupported('setRange', () {
var l = makeElementWithChildren().children;
l.setRange(0, 0, []);
});
testUnsupported('replaceRange', () {
var l = makeElementWithChildren().children;
l.replaceRange(0, 0, []);
});
testUnsupported('removeRange', () {
var l = makeElementWithChildren().children;
l.removeRange(0, 1);
});
testUnsupported('insertAll', () {
var l = makeElementWithChildren().children;
l.insertAll(0, []);
});
});
group('matches', () {
test('matches', () {
var element = new DivElement();
document.body.append(element);
element.classes.add('test');
expect(element.matches('div'), true);
expect(element.matches('span'), false);
expect(element.matches('.test'), true);
});
});
group('querySelectorAll', () {
List<Element> getQuerySelectorAll() {
return new Element.html("""
<div>
<hr/>
<a class='q' href='http://dartlang.org'>Dart!</a>
<p>
<span class='q'>Hello</span>,
<em>world</em>!
</p>
<hr class='q'/>
</div>
""").querySelectorAll('.q');
}
List<Element> getEmptyQuerySelectorAll() =>
new Element.tag('div').querySelectorAll('img');
test('last', () {
expect(getQuerySelectorAll().last, isHRElement);
});
test('forEach', () {
var els = [];
getQuerySelectorAll().forEach((el) => els.add(el));
expect(els[0], isAnchorElement);
expect(els[1], isSpanElement);
expect(els[2], isHRElement);
});
test('map', () {
var texts = getQuerySelectorAll().map((el) => el.text).toList();
expect(texts, equals(['Dart!', 'Hello', '']));
});
test('where', () {
var filtered =
getQuerySelectorAll().where((n) => n is SpanElement).toList();
expect(filtered.length, 1);
expect(filtered[0], isSpanElement);
expect(filtered, isElementList);
});
test('every', () {
var el = getQuerySelectorAll();
expect(el.every((n) => n is Element), isTrue);
expect(el.every((n) => n is SpanElement), isFalse);
});
test('any', () {
var el = getQuerySelectorAll();
expect(el.any((n) => n is SpanElement), isTrue);
expect(el.any((n) => n is svg.SvgElement), isFalse);
});
test('isEmpty', () {
expect(getEmptyQuerySelectorAll().isEmpty, isTrue);
expect(getQuerySelectorAll().isEmpty, isFalse);
});
test('length', () {
expect(getEmptyQuerySelectorAll().length, 0);
expect(getQuerySelectorAll().length, 3);
});
test('[]', () {
var els = getQuerySelectorAll();
expect(els[0], isAnchorElement);
expect(els[1], isSpanElement);
expect(els[2], isHRElement);
});
test('iterator', () {
var els = [];
for (var subel in getQuerySelectorAll()) {
els.add(subel);
}
expect(els[0], isAnchorElement);
expect(els[1], isSpanElement);
expect(els[2], isHRElement);
});
test('sublist', () {
expect(getQuerySelectorAll().sublist(1, 2) is List<Element>, isTrue);
});
testUnsupported(
'[]=', () => getQuerySelectorAll()[1] = new Element.tag('br'));
testUnsupported(
'add', () => getQuerySelectorAll().add(new Element.tag('br')));
testUnsupported('addAll', () {
getQuerySelectorAll().addAll([
new Element.tag('span'),
new Element.tag('a'),
new Element.tag('h1')
]);
});
testUnsupported('sort', () => getQuerySelectorAll().sort((a1, a2) => 0));
testUnsupported('setRange', () {
getQuerySelectorAll().setRange(0, 1, [new BRElement()]);
});
testUnsupported(
'removeRange', () => getQuerySelectorAll().removeRange(0, 1));
testUnsupported('clear', () => getQuerySelectorAll().clear());
testUnsupported('removeLast', () => getQuerySelectorAll().removeLast());
});
group('functional', () {
test('toString', () {
final elems = makeElementWithChildren().children;
expect(elems.toString(), "[br, img, input]");
final elem = makeElement().children;
expect(elem.toString(), '[]');
});
test('scrollIntoView', () {
var child = new DivElement();
document.body.append(child);
child.scrollIntoView(ScrollAlignment.TOP);
child.scrollIntoView(ScrollAlignment.BOTTOM);
child.scrollIntoView(ScrollAlignment.CENTER);
child.scrollIntoView();
});
});
group('_ElementList', () {
List<Element> makeElList() => makeElementWithChildren().children;
test('where', () {
var filtered = makeElList().where((n) => n is ImageElement);
expect(filtered.length, 1);
expect(filtered.first, isImageElement);
expect(filtered, isElementIterable);
});
test('sublist', () {
var range = makeElList().sublist(1, 3);
expect(range, isElementList);
expect(range[0], isImageElement);
expect(range[1], isInputElement);
});
});
group('eventDelegation', () {
test('matches', () {
Element clickOne = new Element.a();
Element selectorOne = new Element.div()
..classes.add('selector')
..children.add(clickOne);
Element clickTwo = new Element.a();
Element selectorTwo = new Element.div()
..classes.add('selector')
..children.add(clickTwo);
document.body.append(selectorOne);
document.body.append(selectorTwo);
document.body.onClick
.matches('.selector')
.listen(expectAsync1((Event event) {
expect(event.currentTarget, document.body);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
}));
selectorOne.onClick
.matches('.selector')
.listen(expectAsync1((Event event) {
expect(event.currentTarget, selectorOne);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
}));
clickOne.click();
Element elem = new Element.div()..classes.addAll(['a', 'b']);
Element img = new Element.img()
..classes.addAll(['b', 'a', 'd'])
..id = 'cookie';
Element input = new InputElement()..classes.addAll(['c', 'd']);
var div = new Element.div()
..classes.add('a')
..id = 'wat';
document.body.append(elem);
document.body.append(img);
document.body.append(input);
document.body.append(div);
Element elem4 = new Element.div()..classes.addAll(['i', 'j']);
Element elem5 = new Element.div()
..classes.addAll(['g', 'h'])
..children.add(elem4);
Element elem6 = new Element.div()
..classes.addAll(['e', 'f'])
..children.add(elem5);
document.body.append(elem6);
var firedEvent = false;
var elems = querySelectorAll('.a');
querySelectorAll('.a').onClick.listen((event) {
firedEvent = true;
});
expect(firedEvent, false);
querySelector('.c').click();
expect(firedEvent, false);
querySelector('#wat').click();
expect(firedEvent, true);
var firedEvent4 = false;
querySelectorAll('.a').onClick.matches('.d').listen((event) {
firedEvent4 = true;
});
expect(firedEvent4, false);
querySelector('.c').click();
expect(firedEvent4, false);
querySelector('#wat').click();
expect(firedEvent4, false);
querySelector('#cookie').click();
expect(firedEvent4, true);
var firedEvent2 = false;
querySelectorAll('.a').onClick.listen((event) {
firedEvent2 = true;
});
Element elem2 = new Element.html('<div class="a"><br/>');
document.body.append(elem2);
elem2.click();
expect(firedEvent2, false);
elem2.classes.add('a');
elem2.click();
expect(firedEvent2, false);
var firedEvent3 = false;
querySelectorAll(':root').onClick.matches('.a').listen((event) {
firedEvent3 = true;
});
Element elem3 = new Element.html('<div class="d"><br/>');
document.body.append(elem3);
elem3.click();
expect(firedEvent3, false);
elem3.classes.add('a');
elem3.click();
expect(firedEvent3, true);
var firedEvent5 = false;
querySelectorAll(':root').onClick.matches('.e').listen((event) {
firedEvent5 = true;
});
expect(firedEvent5, false);
querySelector('.i').click();
expect(firedEvent5, true);
});
test('event ordering', () {
var a = new DivElement();
var b = new DivElement();
a.append(b);
var c = new DivElement();
b.append(c);
var eventOrder = [];
ElementStream aEvent = a.on['custom_event'];
aEvent.listen((_) {
eventOrder.add('a no-capture');
});
aEvent.capture((_) {
eventOrder.add('a capture');
});
ElementStream bEvent = b.on['custom_event'];
bEvent.listen((_) {
eventOrder.add('b no-capture');
});
bEvent.capture((_) {
eventOrder.add('b capture');
});
document.body.append(a);
var event = new Event('custom_event', canBubble: true);
c.dispatchEvent(event);
expect(eventOrder,
['a capture', 'b capture', 'b no-capture', 'a no-capture']);
});
});
group('ElementList', () {
// Tests for methods on the DOM class 'NodeList'.
//
// There are two interesting things that are validated here from the
// viewpoint of the dart2js implementation of a 'native' class:
//
// 1. Some methods are implemented from by 'Object' or 'Interceptor';
// some of these tests validate that a method can be called.
// 2. Some methods are implemented by mixins.
ElementList<Element> makeElementList() =>
(new Element.html("<div>Foo<br/><!--baz--><br/><br/></div>"))
.querySelectorAll('br');
test('hashCode', () {
var nodes = makeElementList();
var hash = nodes.hashCode;
final int N = 1000;
int matchCount = 0;
for (int i = 0; i < N; i++) {
if (makeElementList().hashCode == hash) matchCount++;
}
expect(matchCount, lessThan(N));
});
test('operator==', () {
var a = [makeElementList(), makeElementList(), null];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
expect(i == j, a[i] == a[j]);
}
}
});
test('runtimeType', () {
var nodes1 = makeElementList();
var nodes2 = makeElementList();
var type1 = nodes1.runtimeType;
var type2 = nodes2.runtimeType;
expect(type1 == type2, true);
String name = '$type1';
if (name.length > 3) {
expect(name.contains('ElementList'), true);
}
});
test('first', () {
var nodes = makeElementList();
expect(nodes.first, isBRElement);
});
test('last', () {
var nodes = makeElementList();
expect(nodes.last, isBRElement);
});
test('where', () {
var filtered = makeElementList().where((n) => n is BRElement).toList();
expect(filtered.length, 3);
expect(filtered[0], isBRElement);
});
test('sublist', () {
var range = makeElementList().sublist(1, 3);
expect(range.length, 2);
expect(range[0], isBRElement);
expect(range[1], isBRElement);
});
});
}