blob: fbbd642c2151e72c702bdfdabe72b5e8ab88b1c2 [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.
#library('DocumentFragmentTest');
#import('../../pkg/unittest/unittest.dart');
#import('../../pkg/unittest/html_config.dart');
#import('dart:html');
#source('util.dart');
main() {
useHtmlConfiguration();
Collection<String> _nodeStrings(Collection<Node> input) {
var out = new List<String>();
for (Node n in input) {
if (n is Element) {
Element e = n;
out.add(e.tagName);
} else {
out.add(n.text);
}
}
return out;
};
assertConstError(void fn()) {
try {
fn();
} catch (e) {
if (e is IllegalAccessException || e is UnsupportedOperationException) {
return;
}
}
Expect.fail('Expected immutability error');
};
void expectEmptyStyleDeclaration(CSSStyleDeclaration style) {
Expect.equals("", style.cssText);
Expect.equals("", style.getPropertyPriority('color'));
Expect.equals("", style.item(0));
Expect.equals(0, style.length);
// TODO(jacobr): these checks throw NotImplementedExceptions in dartium.
// Expect.isNull(style.parentRule);
// Expect.isNull(style.getPropertyCSSValue('color'));
// Expect.isNull(style.getPropertyShorthand('color'));
// Expect.isFalse(style.isPropertyImplicit('color'));
// Ideally these would throw errors, but it's not possible to create a class
// that'll intercept these calls without implementing the entire
// CSSStyleDeclaration interface, so we'll settle for them being no-ops.
style.cssText = '* {color: blue}';
style.removeProperty('color');
style.setProperty('color', 'blue');
}
group('constructors', () {
test('0-argument makes an empty fragment', () {
final fragment = new DocumentFragment();
Expect.listEquals([], fragment.elements);
});
test('.html parses input as HTML', () {
final fragment = new DocumentFragment.html('<a>foo</a>');
Expect.isTrue(fragment.elements[0] is AnchorElement);
});
// test('.svg parses input as SVG', () {
// final fragment = new DocumentFragment.svg('<a>foo</a>');
// Expect.isTrue(fragment.elements[0] is SVGAElement);
// });
// TODO(nweiz): enable this once XML is ported.
// test('.xml parses input as XML', () {
// final fragment = new DocumentFragment.xml('<a>foo</a>');
// Expect.isTrue(fragment.elements[0] is XMLElement);
// });
});
test('Unsupported operations throw errors', () {
var emptyFragment = new DocumentFragment();
expectUnsupported(() => emptyFragment.attributes = {});
expectUnsupported(() => emptyFragment.classes = []);
expectUnsupported(() => emptyFragment.classes.add('foo'));
expectUnsupported(() => emptyFragment.dataAttributes = {});
expectUnsupported(() => emptyFragment.contentEditable = "true");
expectUnsupported(() => emptyFragment.dir);
expectUnsupported(() => emptyFragment.dir = "ltr");
expectUnsupported(() => emptyFragment.draggable = true);
expectUnsupported(() => emptyFragment.hidden = true);
expectUnsupported(() => emptyFragment.id = "foo");
expectUnsupported(() => emptyFragment.lang);
expectUnsupported(() => emptyFragment.lang = "en");
expectUnsupported(() => emptyFragment.scrollLeft = 10);
expectUnsupported(() => emptyFragment.scrollTop = 10);
expectUnsupported(() => emptyFragment.spellcheck = true);
expectUnsupported(() => emptyFragment.translate = true);
expectUnsupported(() => emptyFragment.tabIndex = 5);
expectUnsupported(() => emptyFragment.title = "foo");
expectUnsupported(() => emptyFragment.webkitdropzone = "foo");
expectUnsupported(() => emptyFragment.webkitRegionOverflow = "foo");
});
group('elements', () {
var fragment;
var elements;
init() {
fragment = new DocumentFragment();
elements = fragment.elements;
fragment.nodes.addAll(
[new Text("1"), new Element.tag("A"), new Element.tag("B"),
new Text("2"), new Element.tag("I"), new Text("3"),
new Element.tag("U")]);
};
test('is initially empty', () {
elements = new DocumentFragment().elements;
Expect.listEquals([], elements);
Expect.isTrue(elements.isEmpty());
});
test('filters out non-element nodes', () {
init();
Expect.listEquals(["1", "A", "B", "2", "I", "3", "U"],
_nodeStrings(fragment.nodes));
Expect.listEquals(["A", "B", "I", "U"], _nodeStrings(elements));
});
test('only indexes elements, not other nodes', () {
init();
elements[1] = new Element.tag("BR");
Expect.listEquals(["1", "A", "BR", "2", "I", "3", "U"],
_nodeStrings(fragment.nodes));
Expect.listEquals(["A", "BR", "I", "U"], _nodeStrings(elements));
});
test('adds to both elements and nodes', () {
init();
elements.add(new Element.tag("UL"));
Expect.listEquals(["1", "A", "B", "2", "I", "3", "U", "UL"],
_nodeStrings(fragment.nodes));
Expect.listEquals(["A", "B", "I", "U", "UL"], _nodeStrings(elements));
});
test('removes only elements, from both elements and nodes', () {
init();
Expect.equals("U", elements.removeLast().tagName);
Expect.listEquals(["1", "A", "B", "2", "I", "3"],
_nodeStrings(fragment.nodes));
Expect.listEquals(["A", "B", "I"], _nodeStrings(elements));
Expect.equals("I", elements.removeLast().tagName);
Expect.listEquals(["1", "A", "B", "2", "3"],
_nodeStrings(fragment.nodes));
Expect.listEquals(["A", "B"], _nodeStrings(elements));
});
test('accessors are wrapped', () {
init();
Expect.equals("A", elements[0].tagName);
Expect.listEquals(
["I"], _nodeStrings(elements.filter((e) => e.tagName == "I")));
Expect.isTrue(elements.every((e) => e is Element));
Expect.isTrue(elements.some((e) => e.tagName == "U"));
Expect.isFalse(elements.isEmpty());
Expect.equals(4, elements.length);
Expect.equals("I", elements[2].tagName);
Expect.equals("U", elements.last().tagName);
});
test('setting elements overwrites nodes as well', () {
init();
fragment.elements = [new Element.tag("DIV"), new Element.tag("HEAD")];
Expect.listEquals(["DIV", "HEAD"], _nodeStrings(fragment.nodes));
});
});
test('setting innerHTML works', () {
var fragment = new DocumentFragment();
fragment.nodes.add(new Text("foo"));
fragment.innerHTML = "<a>bar</a>baz";
Expect.listEquals(["A", "baz"], _nodeStrings(fragment.nodes));
});
test('getting innerHTML works', () {
var fragment = new DocumentFragment();
fragment.nodes.addAll([new Text("foo"), new Element.html("<A>bar</A>")]);
Expect.equals("foo<a>bar</a>", fragment.innerHTML);
Expect.equals("foo<a>bar</a>", fragment.outerHTML);
});
group('insertAdjacentElement', () {
getFragment() => new DocumentFragment.html("<a>foo</a>");
test('beforeBegin does nothing', () {
var fragment = getFragment();
Expect.isNull(
fragment.insertAdjacentElement("beforeBegin", new Element.tag("b")));
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterEnd does nothing', () {
var fragment = getFragment();
Expect.isNull(
fragment.insertAdjacentElement("afterEnd", new Element.tag("b")));
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterBegin inserts the element', () {
var fragment = getFragment();
var el = new Element.tag("b");
Expect.equals(el, fragment.insertAdjacentElement("afterBegin", el));
Expect.equals("<b></b><a>foo</a>", fragment.innerHTML);
});
test('beforeEnd inserts the element', () {
var fragment = getFragment();
var el = new Element.tag("b");
Expect.equals(el, fragment.insertAdjacentElement("beforeEnd", el));
Expect.equals("<a>foo</a><b></b>", fragment.innerHTML);
});
});
group('insertAdjacentText', () {
getFragment() => new DocumentFragment.html("<a>foo</a>");
test('beforeBegin does nothing', () {
var fragment = getFragment();
fragment.insertAdjacentText("beforeBegin", "foo");
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterEnd does nothing', () {
var fragment = getFragment();
fragment.insertAdjacentText("afterEnd", "foo");
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterBegin inserts the text', () {
var fragment = getFragment();
fragment.insertAdjacentText("afterBegin", "foo");
Expect.equals("foo<a>foo</a>", fragment.innerHTML);
});
test('beforeEnd inserts the text', () {
var fragment = getFragment();
fragment.insertAdjacentText("beforeEnd", "foo");
Expect.equals("<a>foo</a>foo", fragment.innerHTML);
});
});
group('insertAdjacentHTML', () {
getFragment() => new DocumentFragment.html("<a>foo</a>");
test('beforeBegin does nothing', () {
var fragment = getFragment();
fragment.insertAdjacentHTML("beforeBegin", "foo<br>");
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterEnd does nothing', () {
var fragment = getFragment();
fragment.insertAdjacentHTML("afterEnd", "<br>foo");
Expect.equals("<a>foo</a>", fragment.innerHTML);
});
test('afterBegin inserts the HTML', () {
var fragment = getFragment();
fragment.insertAdjacentHTML("afterBegin", "foo<br>");
Expect.equals("foo<br><a>foo</a>", fragment.innerHTML);
});
test('beforeEnd inserts the HTML', () {
var fragment = getFragment();
fragment.insertAdjacentHTML("beforeEnd", "<br>foo");
Expect.equals("<a>foo</a><br>foo", fragment.innerHTML);
});
});
// Just test that these methods don't throw errors
test("no-op methods don't throw errors", () {
var fragment = new DocumentFragment();
fragment.on.click.add((e) => null);
fragment.blur();
fragment.focus();
fragment.click();
fragment.scrollByLines(2);
fragment.scrollByPages(2);
fragment.scrollIntoView();
fragment.webkitRequestFullScreen(2);
});
test('default values', () {
var fragment = new DocumentFragment();
fragment.rect.then(expectAsync1((ElementRect rect) {
expectEmptyRect(rect.client);
expectEmptyRect(rect.offset);
expectEmptyRect(rect.scroll);
expectEmptyRect(rect.bounding);
Expect.isTrue(rect.clientRects.isEmpty());
}));
Expect.equals("false", fragment.contentEditable);
Expect.equals(-1, fragment.tabIndex);
Expect.equals("", fragment.id);
Expect.equals("", fragment.title);
Expect.equals("", fragment.tagName);
Expect.equals("", fragment.webkitdropzone);
Expect.equals("", fragment.webkitRegionOverflow);
Expect.isFalse(fragment.isContentEditable);
Expect.isFalse(fragment.draggable);
Expect.isFalse(fragment.hidden);
Expect.isFalse(fragment.spellcheck);
Expect.isFalse(fragment.translate);
Expect.isNull(fragment.nextElementSibling);
Expect.isNull(fragment.previousElementSibling);
Expect.isNull(fragment.offsetParent);
Expect.isNull(fragment.parent);
Expect.isTrue(fragment.attributes.isEmpty());
Expect.isTrue(fragment.classes.isEmpty());
Expect.isTrue(fragment.dataAttributes.isEmpty());
Expect.isFalse(fragment.matchesSelector("foo"));
Expect.isFalse(fragment.matchesSelector("*"));
});
test('style', () {
var fragment = new DocumentFragment();
var style = fragment.style;
expectEmptyStyleDeclaration(style);
fragment.computedStyle.then(expectAsync1((computedStyle) {
expectEmptyStyleDeclaration(computedStyle);
}));
});
// TODO(nweiz): re-enable when const is better supported in dartc and/or frog
// test('const fields are immutable', () {
// var fragment = new DocumentFragment();
// assertConstError(() => fragment.attributes['title'] = 'foo');
// assertConstError(() => fragment.dataAttributes['title'] = 'foo');
// fragment.rect.then((ElementRect rect) {
// assertConstError(() => rect.clientRects.add(null));
// callbackDone();
// });
// // Issue 174: #classes is currently not const
// // assertConstError(() => fragment.classes.add('foo'));
// });
test('query searches the fragment', () {
var fragment = new DocumentFragment.html(
"<div class='foo'><a>foo</a><b>bar</b></div>");
Expect.equals("A", fragment.query(".foo a").tagName);
Expect.listEquals(["A", "B"], _nodeStrings(fragment.queryAll(".foo *")));
});
}