mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
73b325c419
Change-Id: Ie7477c232f3f28c7fe597da7d5338ac27a2e33ee Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/140201 Reviewed-by: Bob Nystrom <rnystrom@google.com>
998 lines
31 KiB
Dart
998 lines
31 KiB
Dart
// 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.
|
|
|
|
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>''') as 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 as 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 as 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 as 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 as 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 as 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 as 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 as 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 as 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'] as ElementStream;
|
|
aEvent.listen((_) {
|
|
eventOrder.add('a no-capture');
|
|
});
|
|
|
|
aEvent.capture((_) {
|
|
eventOrder.add('a capture');
|
|
});
|
|
|
|
ElementStream bEvent = b.on['custom_event'] as ElementStream;
|
|
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);
|
|
});
|
|
});
|
|
}
|