mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
dom: implement element.*Attribute
This commit is contained in:
@@ -2,6 +2,10 @@ const std = @import("std");
|
|||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
|
const jsruntime = @import("jsruntime");
|
||||||
|
const Case = jsruntime.test_utils.Case;
|
||||||
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
|
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
const HTMLElem = @import("../html/elements.zig");
|
const HTMLElem = @import("../html/elements.zig");
|
||||||
pub const Union = @import("../html/elements.zig").Union;
|
pub const Union = @import("../html/elements.zig").Union;
|
||||||
@@ -22,4 +26,50 @@ pub const Element = struct {
|
|||||||
pub fn get_localName(self: *parser.Element) ![]const u8 {
|
pub fn get_localName(self: *parser.Element) ![]const u8 {
|
||||||
return try parser.elementLocalName(self);
|
return try parser.elementLocalName(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn _getAttribute(self: *parser.Element, qname: []const u8) !?[]const u8 {
|
||||||
|
return try parser.elementGetAttribute(self, qname);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _setAttribute(self: *parser.Element, qname: []const u8, value: []const u8) !void {
|
||||||
|
return try parser.elementSetAttribute(self, qname, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _removeAttribute(self: *parser.Element, qname: []const u8) !void {
|
||||||
|
return try parser.elementRemoveAttribute(self, qname);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _hasAttribute(self: *parser.Element, qname: []const u8) !bool {
|
||||||
|
return try parser.elementHasAttribute(self, qname);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
pub fn testExecFn(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
comptime _: []jsruntime.API,
|
||||||
|
) !void {
|
||||||
|
var attribute = [_]Case{
|
||||||
|
.{ .src = "let div = document.getElementById('content')", .ex = "undefined" },
|
||||||
|
.{ .src = "div.getAttribute('id')", .ex = "content" },
|
||||||
|
|
||||||
|
.{ .src = "div.hasAttribute('foo')", .ex = "false" },
|
||||||
|
.{ .src = "div.getAttribute('foo')", .ex = "null" },
|
||||||
|
|
||||||
|
.{ .src = "div.setAttribute('foo', 'bar')", .ex = "undefined" },
|
||||||
|
.{ .src = "div.hasAttribute('foo')", .ex = "true" },
|
||||||
|
.{ .src = "div.getAttribute('foo')", .ex = "bar" },
|
||||||
|
|
||||||
|
.{ .src = "div.setAttribute('foo', 'baz')", .ex = "undefined" },
|
||||||
|
.{ .src = "div.hasAttribute('foo')", .ex = "true" },
|
||||||
|
.{ .src = "div.getAttribute('foo')", .ex = "baz" },
|
||||||
|
|
||||||
|
.{ .src = "div.removeAttribute('foo')", .ex = "undefined" },
|
||||||
|
.{ .src = "div.hasAttribute('foo')", .ex = "false" },
|
||||||
|
.{ .src = "div.getAttribute('foo')", .ex = "null" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &attribute);
|
||||||
|
}
|
||||||
|
|||||||
@@ -749,6 +749,34 @@ pub fn elementGetAttribute(elem: *Element, name: []const u8) !?[]const u8 {
|
|||||||
return stringToData(s.?);
|
return stringToData(s.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn elementSetAttribute(elem: *Element, qname: []const u8, value: []const u8) !void {
|
||||||
|
const err = elementVtable(elem).dom_element_set_attribute.?(
|
||||||
|
elem,
|
||||||
|
try stringFromData(qname),
|
||||||
|
try stringFromData(value),
|
||||||
|
);
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elementRemoveAttribute(elem: *Element, qname: []const u8) !void {
|
||||||
|
const err = elementVtable(elem).dom_element_remove_attribute.?(
|
||||||
|
elem,
|
||||||
|
try stringFromData(qname),
|
||||||
|
);
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elementHasAttribute(elem: *Element, qname: []const u8) !bool {
|
||||||
|
var res: bool = undefined;
|
||||||
|
const err = elementVtable(elem).dom_element_has_attribute.?(
|
||||||
|
elem,
|
||||||
|
try stringFromData(qname),
|
||||||
|
&res,
|
||||||
|
);
|
||||||
|
try DOMErr(err);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn elementHasClass(elem: *Element, class: []const u8) !bool {
|
pub fn elementHasClass(elem: *Element, class: []const u8) !bool {
|
||||||
var res: bool = undefined;
|
var res: bool = undefined;
|
||||||
const err = elementVtable(elem).dom_element_has_class.?(
|
const err = elementVtable(elem).dom_element_has_class.?(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const HTMLDocumentTestExecFn = @import("html/document.zig").testExecFn;
|
|||||||
const nodeTestExecFn = @import("dom/node.zig").testExecFn;
|
const nodeTestExecFn = @import("dom/node.zig").testExecFn;
|
||||||
const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn;
|
const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn;
|
||||||
const textTestExecFn = @import("dom/text.zig").testExecFn;
|
const textTestExecFn = @import("dom/text.zig").testExecFn;
|
||||||
|
const elementTestExecFn = @import("dom/element.zig").testExecFn;
|
||||||
const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn;
|
const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn;
|
||||||
const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn;
|
const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn;
|
||||||
const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn;
|
const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn;
|
||||||
@@ -56,6 +57,7 @@ fn testsAllExecFn(
|
|||||||
nodeTestExecFn,
|
nodeTestExecFn,
|
||||||
characterDataTestExecFn,
|
characterDataTestExecFn,
|
||||||
textTestExecFn,
|
textTestExecFn,
|
||||||
|
elementTestExecFn,
|
||||||
HTMLCollectionTestExecFn,
|
HTMLCollectionTestExecFn,
|
||||||
DOMExceptionTestExecFn,
|
DOMExceptionTestExecFn,
|
||||||
DOMImplementationExecFn,
|
DOMImplementationExecFn,
|
||||||
|
|||||||
32
tests/wpt/dom/nodes/Element-hasAttribute.html
Normal file
32
tests/wpt/dom/nodes/Element-hasAttribute.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Element.prototype.hasAttribute</title>
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#dom-element-hasattribute">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<span data-e2="2" data-F2="3" id="t"></span>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.setAttributeNS("foo", "x", "first");
|
||||||
|
|
||||||
|
assert_true(el.hasAttribute("x"));
|
||||||
|
|
||||||
|
}, "hasAttribute should check for attribute presence, irrespective of namespace");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
|
||||||
|
const el = document.getElementById("t");
|
||||||
|
|
||||||
|
assert_true(el.hasAttribute("data-e2"));
|
||||||
|
assert_true(el.hasAttribute("data-E2"));
|
||||||
|
assert_true(el.hasAttribute("data-f2"));
|
||||||
|
assert_true(el.hasAttribute("data-F2"));
|
||||||
|
|
||||||
|
}, "hasAttribute should work with all attribute casings");
|
||||||
|
</script>
|
||||||
40
tests/wpt/dom/nodes/Element-hasAttributes.html
Normal file
40
tests/wpt/dom/nodes/Element-hasAttributes.html
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title></title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button></button>
|
||||||
|
<div id="foo"></div>
|
||||||
|
<p data-foo=""></p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
var buttonElement = document.getElementsByTagName('button')[0];
|
||||||
|
assert_equals(buttonElement.hasAttributes(), false, 'hasAttributes() on empty element must return false.');
|
||||||
|
|
||||||
|
var emptyDiv = document.createElement('div');
|
||||||
|
assert_equals(emptyDiv.hasAttributes(), false, 'hasAttributes() on dynamically created empty element must return false.');
|
||||||
|
|
||||||
|
}, 'element.hasAttributes() must return false when the element does not have attribute.');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var divWithId = document.getElementById('foo');
|
||||||
|
assert_equals(divWithId.hasAttributes(), true, 'hasAttributes() on element with id attribute must return true.');
|
||||||
|
|
||||||
|
var divWithClass = document.createElement('div');
|
||||||
|
divWithClass.setAttribute('class', 'foo');
|
||||||
|
assert_equals(divWithClass.hasAttributes(), true, 'hasAttributes() on dynamically created element with class attribute must return true.');
|
||||||
|
|
||||||
|
var pWithCustomAttr = document.getElementsByTagName('p')[0];
|
||||||
|
assert_equals(pWithCustomAttr.hasAttributes(), true, 'hasAttributes() on element with custom attribute must return true.');
|
||||||
|
|
||||||
|
var divWithCustomAttr = document.createElement('div');
|
||||||
|
divWithCustomAttr.setAttribute('data-custom', 'foo');
|
||||||
|
assert_equals(divWithCustomAttr.hasAttributes(), true, 'hasAttributes() on dynamically created element with custom attribute must return true.');
|
||||||
|
|
||||||
|
}, 'element.hasAttributes() must return true when the element has attribute.');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
58
tests/wpt/dom/nodes/Element-removeAttribute.html
Normal file
58
tests/wpt/dom/nodes/Element-removeAttribute.html
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Element.prototype.removeAttribute</title>
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#dom-element-removeattribute">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.setAttribute("x", "first");
|
||||||
|
el.setAttributeNS("foo", "x", "second");
|
||||||
|
|
||||||
|
assert_equals(el.attributes.length, 2);
|
||||||
|
assert_equals(el.getAttribute("x"), "first");
|
||||||
|
assert_equals(el.getAttributeNS(null, "x"), "first");
|
||||||
|
assert_equals(el.getAttributeNS("foo", "x"), "second");
|
||||||
|
|
||||||
|
// removeAttribute removes the first attribute with name "x" that
|
||||||
|
// we set on the element, irrespective of namespace.
|
||||||
|
el.removeAttribute("x");
|
||||||
|
|
||||||
|
// The only attribute remaining should be the second one.
|
||||||
|
assert_equals(el.getAttribute("x"), "second");
|
||||||
|
assert_equals(el.getAttributeNS(null, "x"), null);
|
||||||
|
assert_equals(el.getAttributeNS("foo", "x"), "second");
|
||||||
|
assert_equals(el.attributes.length, 1, "one attribute");
|
||||||
|
|
||||||
|
}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " +
|
||||||
|
"not in a namespace");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.setAttributeNS("foo", "x", "first");
|
||||||
|
el.setAttributeNS("foo2", "x", "second");
|
||||||
|
|
||||||
|
assert_equals(el.attributes.length, 2);
|
||||||
|
assert_equals(el.getAttribute("x"), "first");
|
||||||
|
assert_equals(el.getAttributeNS("foo", "x"), "first");
|
||||||
|
assert_equals(el.getAttributeNS("foo2", "x"), "second");
|
||||||
|
|
||||||
|
// removeAttribute removes the first attribute with name "x" that
|
||||||
|
// we set on the element, irrespective of namespace.
|
||||||
|
el.removeAttribute("x");
|
||||||
|
|
||||||
|
// The only attribute remaining should be the second one.
|
||||||
|
assert_equals(el.getAttribute("x"), "second");
|
||||||
|
assert_equals(el.getAttributeNS("foo", "x"), null);
|
||||||
|
assert_equals(el.getAttributeNS("foo2", "x"), "second");
|
||||||
|
assert_equals(el.attributes.length, 1, "one attribute");
|
||||||
|
|
||||||
|
}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " +
|
||||||
|
"in a namespace");
|
||||||
|
</script>
|
||||||
18
tests/wpt/dom/nodes/Element-removeAttributeNS.html
Normal file
18
tests/wpt/dom/nodes/Element-removeAttributeNS.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<title>Element.removeAttributeNS</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="attributes.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
var XML = "http://www.w3.org/XML/1998/namespace"
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS(XML, "a:bb", "pass")
|
||||||
|
attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb")
|
||||||
|
el.removeAttributeNS(XML, "a:bb")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb")
|
||||||
|
}, "removeAttributeNS should take a local name.")
|
||||||
|
</script>
|
||||||
22
tests/wpt/dom/nodes/Element-setAttribute-crbug-1138487.html
Normal file
22
tests/wpt/dom/nodes/Element-setAttribute-crbug-1138487.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
// Regression test for crbug.com/1138487.
|
||||||
|
//
|
||||||
|
// It was possible for a non-ASCII-lowercase string to be used when inserting
|
||||||
|
// into the attribute collection if a hashtable encountered it during probing
|
||||||
|
// while looking for the ASCII-lowercase equivalent.
|
||||||
|
//
|
||||||
|
// This caused such a string to be illegally used as an attribute name, thus
|
||||||
|
// causing inconsistent behavior in future attribute lookup.
|
||||||
|
test(() => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.setAttribute('labelXQL', 'abc');
|
||||||
|
el.setAttribute('_valueXQL', 'def');
|
||||||
|
assert_equals(el.getAttribute('labelXQL'), 'abc');
|
||||||
|
assert_equals(el.getAttribute('labelxql'), 'abc');
|
||||||
|
assert_equals(el.getAttribute('_valueXQL'), 'def');
|
||||||
|
assert_equals(el.getAttribute('_valuexql'), 'def');
|
||||||
|
}, "Attributes first seen in mixed ASCII case should not be corrupted.");
|
||||||
|
</script>
|
||||||
38
tests/wpt/dom/nodes/Element-setAttribute.html
Normal file
38
tests/wpt/dom/nodes/Element-setAttribute.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Element.prototype.setAttribute</title>
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.setAttributeNS("foo", "x", "first");
|
||||||
|
el.setAttributeNS("foo2", "x", "second");
|
||||||
|
|
||||||
|
el.setAttribute("x", "changed");
|
||||||
|
|
||||||
|
assert_equals(el.attributes.length, 2);
|
||||||
|
assert_equals(el.getAttribute("x"), "changed");
|
||||||
|
assert_equals(el.getAttributeNS("foo", "x"), "changed");
|
||||||
|
assert_equals(el.getAttributeNS("foo2", "x"), "second");
|
||||||
|
|
||||||
|
}, "setAttribute should change the first attribute, irrespective of namespace");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
// https://github.com/whatwg/dom/issues/31
|
||||||
|
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.setAttribute("FOO", "bar");
|
||||||
|
|
||||||
|
assert_equals(el.getAttribute("foo"), "bar");
|
||||||
|
assert_equals(el.getAttribute("FOO"), "bar");
|
||||||
|
assert_equals(el.getAttributeNS("", "foo"), "bar");
|
||||||
|
assert_equals(el.getAttributeNS("", "FOO"), null);
|
||||||
|
|
||||||
|
}, "setAttribute should lowercase before setting");
|
||||||
|
</script>
|
||||||
858
tests/wpt/dom/nodes/attributes.html
Normal file
858
tests/wpt/dom/nodes/attributes.html
Normal file
@@ -0,0 +1,858 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>Attributes tests</title>
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#attr">
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute">
|
||||||
|
<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattributens">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="attributes.js"></script>
|
||||||
|
<script src="productions.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<span id="test1"></span>
|
||||||
|
<span class="&<>foo"></span>
|
||||||
|
<span id="test2">
|
||||||
|
<span ~=""></span>
|
||||||
|
<span ~></span>
|
||||||
|
<span></span>
|
||||||
|
</span>
|
||||||
|
<script>
|
||||||
|
var XML = "http://www.w3.org/XML/1998/namespace"
|
||||||
|
var XMLNS = "http://www.w3.org/2000/xmlns/"
|
||||||
|
|
||||||
|
// toggleAttribute exhaustive tests
|
||||||
|
// Step 1
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0; i < invalid_names.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], true) })
|
||||||
|
}
|
||||||
|
for (var i = 0; i < invalid_names.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i]) })
|
||||||
|
}
|
||||||
|
for (var i = 0; i < invalid_names.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], false) })
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.getElementById("test2")
|
||||||
|
for (var i = 0; i < el.children.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() {
|
||||||
|
el.children[i].toggleAttribute("~", false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (var i = 0; i < el.children.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() {
|
||||||
|
el.children[i].toggleAttribute("~")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (var i = 0; i < el.children.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() {
|
||||||
|
el.children[i].toggleAttribute("~", true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " +
|
||||||
|
"is already present. (toggleAttribute)")
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
assert_true(el.toggleAttribute("ALIGN"))
|
||||||
|
assert_true(!el.hasAttributeNS("", "ALIGN"))
|
||||||
|
assert_true(el.hasAttributeNS("", "align"))
|
||||||
|
assert_true(el.hasAttribute("align"))
|
||||||
|
assert_true(!el.toggleAttribute("ALIGN"))
|
||||||
|
assert_true(!el.hasAttributeNS("", "ALIGN"))
|
||||||
|
assert_true(!el.hasAttributeNS("", "align"))
|
||||||
|
assert_true(!el.hasAttribute("align"))
|
||||||
|
}, "toggleAttribute should lowercase its name argument (upper case attribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
assert_true(el.toggleAttribute("CHEEseCaKe"))
|
||||||
|
assert_true(!el.hasAttributeNS("", "CHEEseCaKe"))
|
||||||
|
assert_true(el.hasAttributeNS("", "cheesecake"))
|
||||||
|
assert_true(el.hasAttribute("cheesecake"))
|
||||||
|
}, "toggleAttribute should lowercase its name argument (mixed case attribute)")
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"]
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert_true(el.toggleAttribute(tests[i]));
|
||||||
|
assert_true(el.hasAttribute(tests[i]));
|
||||||
|
}
|
||||||
|
}, "toggleAttribute should not throw even when qualifiedName starts with 'xmlns'")
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0; i < valid_names.length; i++) {
|
||||||
|
assert_true(el.toggleAttribute(valid_names[i]))
|
||||||
|
assert_true(el.hasAttribute(valid_names[i]))
|
||||||
|
assert_true(!el.toggleAttribute(valid_names[i]))
|
||||||
|
assert_true(!el.hasAttribute(valid_names[i]))
|
||||||
|
// Check using force attr
|
||||||
|
assert_true(el.toggleAttribute(valid_names[i], true))
|
||||||
|
assert_true(el.hasAttribute(valid_names[i]))
|
||||||
|
assert_true(el.toggleAttribute(valid_names[i], true))
|
||||||
|
assert_true(el.hasAttribute(valid_names[i]))
|
||||||
|
assert_true(!el.toggleAttribute(valid_names[i], false))
|
||||||
|
assert_true(!el.hasAttribute(valid_names[i]))
|
||||||
|
}
|
||||||
|
}, "Basic functionality should be intact. (toggleAttribute)")
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.toggleAttribute("a")
|
||||||
|
el.toggleAttribute("b")
|
||||||
|
el.setAttribute("a", "thing")
|
||||||
|
el.toggleAttribute("c")
|
||||||
|
attributes_are(el, [["a", "thing"],
|
||||||
|
["b", ""],
|
||||||
|
["c", ""]])
|
||||||
|
}, "toggleAttribute should not change the order of previously set attributes.")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("baz")
|
||||||
|
el.setAttributeNS("ab", "attr", "fail")
|
||||||
|
el.setAttributeNS("kl", "attr", "pass")
|
||||||
|
el.toggleAttribute("attr")
|
||||||
|
attributes_are(el, [["attr", "pass", "kl"]])
|
||||||
|
}, "toggleAttribute should set the first attribute with the given name")
|
||||||
|
test(function() {
|
||||||
|
// Based on a test by David Flanagan.
|
||||||
|
var el = document.createElement("baz")
|
||||||
|
el.setAttributeNS("foo", "foo:bar", "1");
|
||||||
|
el.setAttributeNS("foo", "foo:bat", "2");
|
||||||
|
assert_equals(el.getAttribute("foo:bar"), "1")
|
||||||
|
assert_equals(el.getAttribute("foo:bat"), "2")
|
||||||
|
attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar")
|
||||||
|
attr_is(el.attributes[1], "2", "bat", "foo", "foo", "foo:bat")
|
||||||
|
el.toggleAttribute("foo:bar");
|
||||||
|
assert_true(!el.hasAttribute("foo:bar"))
|
||||||
|
attr_is(el.attributes[0], "2", "bat", "foo", "foo", "foo:bat")
|
||||||
|
}, "toggleAttribute should set the attribute with the given qualified name")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.style = "color: red; background-color: green"
|
||||||
|
assert_equals(el.toggleAttribute("style"), false)
|
||||||
|
}, "Toggling element with inline style should make inline style disappear")
|
||||||
|
|
||||||
|
// setAttribute exhaustive tests
|
||||||
|
// Step 1
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0; i < invalid_names.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.setAttribute(invalid_names[i], "test") })
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown. (setAttribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.getElementById("test2")
|
||||||
|
for (var i = 0; i < el.children.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() {
|
||||||
|
el.children[i].setAttribute("~", "test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " +
|
||||||
|
"is already present. (setAttribute)")
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("ALIGN", "left")
|
||||||
|
assert_equals(el.getAttributeNS("", "ALIGN"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "align"), "left")
|
||||||
|
assert_equals(el.getAttribute("align"), "left")
|
||||||
|
}, "setAttribute should lowercase its name argument (upper case attribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("CHEEseCaKe", "tasty")
|
||||||
|
assert_equals(el.getAttributeNS("", "CHEEseCaKe"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "cheesecake"), "tasty")
|
||||||
|
assert_equals(el.getAttribute("cheesecake"), "tasty")
|
||||||
|
}, "setAttribute should lowercase its name argument (mixed case attribute)")
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"]
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
el.setAttribute(tests[i], "success");
|
||||||
|
}
|
||||||
|
}, "setAttribute should not throw even when qualifiedName starts with 'xmlns'")
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0; i < valid_names.length; i++) {
|
||||||
|
el.setAttribute(valid_names[i], "test")
|
||||||
|
assert_equals(el.getAttribute(valid_names[i]), "test")
|
||||||
|
}
|
||||||
|
}, "Basic functionality should be intact.")
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttribute("a", "1")
|
||||||
|
el.setAttribute("b", "2")
|
||||||
|
el.setAttribute("a", "3")
|
||||||
|
el.setAttribute("c", "4")
|
||||||
|
attributes_are(el, [["a", "3"],
|
||||||
|
["b", "2"],
|
||||||
|
["c", "4"]])
|
||||||
|
}, "setAttribute should not change the order of previously set attributes.")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("baz")
|
||||||
|
el.setAttributeNS("ab", "attr", "fail")
|
||||||
|
el.setAttributeNS("kl", "attr", "pass")
|
||||||
|
el.setAttribute("attr", "pass")
|
||||||
|
attributes_are(el, [["attr", "pass", "ab"],
|
||||||
|
["attr", "pass", "kl"]])
|
||||||
|
}, "setAttribute should set the first attribute with the given name")
|
||||||
|
test(function() {
|
||||||
|
// Based on a test by David Flanagan.
|
||||||
|
var el = document.createElement("baz")
|
||||||
|
el.setAttributeNS("foo", "foo:bar", "1");
|
||||||
|
assert_equals(el.getAttribute("foo:bar"), "1")
|
||||||
|
attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar")
|
||||||
|
el.setAttribute("foo:bar", "2");
|
||||||
|
assert_equals(el.getAttribute("foo:bar"), "2")
|
||||||
|
attr_is(el.attributes[0], "2", "bar", "foo", "foo", "foo:bar")
|
||||||
|
}, "setAttribute should set the attribute with the given qualified name")
|
||||||
|
|
||||||
|
// setAttributeNS exhaustive tests
|
||||||
|
// Step 1
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0, il = invalid_names.length; i < il; ++i) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR",
|
||||||
|
function() { el.setAttributeNS("a", invalid_names[i], "fail") })
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown. (setAttributeNS)")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.getElementById("test2")
|
||||||
|
for (var i = 0; i < el.children.length; i++) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR", function() {
|
||||||
|
el.children[i].setAttributeNS(null, "~", "test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the Name production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " +
|
||||||
|
"is already present. (setAttributeNS)")
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
for (var i = 0, il = invalid_qnames.length; i < il; ++i) {
|
||||||
|
assert_throws_dom("INVALID_CHARACTER_ERR",
|
||||||
|
function() { el.setAttributeNS("a", invalid_qnames[i], "fail") },
|
||||||
|
"Expected exception for " + invalid_qnames[i] + ".")
|
||||||
|
}
|
||||||
|
}, "When qualifiedName does not match the QName production, an " +
|
||||||
|
"INVALID_CHARACTER_ERR exception is to be thrown.")
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS(null, "aa", "bb")
|
||||||
|
el.setAttributeNS("", "xx", "bb")
|
||||||
|
attributes_are(el, [["aa", "bb"],
|
||||||
|
["xx", "bb"]])
|
||||||
|
}, "null and the empty string should result in a null namespace.")
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS("", "aa:bb", "fail") })
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS(null, "aa:bb", "fail") })
|
||||||
|
}, "A namespace is required to use a prefix.")
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS("a", "xml:bb", "fail") })
|
||||||
|
}, "The xml prefix should not be allowed for arbitrary namespaces")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS(XML, "a:bb", "pass")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb")
|
||||||
|
}, "XML-namespaced attributes don't need an xml prefix")
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS("a", "xmlns:bb", "fail") })
|
||||||
|
}, "The xmlns prefix should not be allowed for arbitrary namespaces")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS("a", "xmlns", "fail") })
|
||||||
|
}, "The xmlns qualified name should not be allowed for arbitrary namespaces")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS("ns", "a:xmlns", "pass")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "pass", "xmlns", "ns", "a", "a:xmlns")
|
||||||
|
}, "xmlns should be allowed as local name")
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS(XMLNS, "a:xmlns", "fail") })
|
||||||
|
assert_throws_dom("NAMESPACE_ERR",
|
||||||
|
function() { el.setAttributeNS(XMLNS, "b:foo", "fail") })
|
||||||
|
}, "The XMLNS namespace should require xmlns as prefix or qualified name")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS(XMLNS, "xmlns:a", "pass")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "pass", "a", XMLNS, "xmlns", "xmlns:a")
|
||||||
|
}, "xmlns should be allowed as prefix in the XMLNS namespace")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS(XMLNS, "xmlns", "pass")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "pass", "xmlns", XMLNS, null, "xmlns")
|
||||||
|
}, "xmlns should be allowed as qualified name in the XMLNS namespace")
|
||||||
|
|
||||||
|
// Step 8-9
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttributeNS("a", "foo:bar", "X")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "X", "bar", "a", "foo", "foo:bar")
|
||||||
|
|
||||||
|
el.setAttributeNS("a", "quux:bar", "Y")
|
||||||
|
assert_equals(el.attributes.length, 1)
|
||||||
|
attr_is(el.attributes[0], "Y", "bar", "a", "foo", "foo:bar")
|
||||||
|
el.removeAttributeNS("a", "bar")
|
||||||
|
}, "Setting the same attribute with another prefix should not change the prefix")
|
||||||
|
|
||||||
|
// Miscellaneous tests
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("iframe")
|
||||||
|
el.setAttribute("src", "file:///home")
|
||||||
|
assert_equals(el.getAttribute("src"), "file:///home")
|
||||||
|
}, "setAttribute should not throw even if a load is not allowed")
|
||||||
|
test(function() {
|
||||||
|
var docFragment = document.createDocumentFragment()
|
||||||
|
var newOne = document.createElement("newElement")
|
||||||
|
newOne.setAttribute("newdomestic", "Yes")
|
||||||
|
docFragment.appendChild(newOne)
|
||||||
|
var domesticNode = docFragment.firstChild
|
||||||
|
var attr = domesticNode.attributes.item(0)
|
||||||
|
attr_is(attr, "Yes", "newdomestic", null, null, "newdomestic")
|
||||||
|
}, "Attributes should work in document fragments.")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("foo")
|
||||||
|
el.setAttribute("x", "y")
|
||||||
|
var attr = el.attributes[0]
|
||||||
|
attr.value = "Y<"
|
||||||
|
attr_is(attr, "Y<", "x", null, null, "x")
|
||||||
|
assert_equals(el.getAttribute("x"), "Y<")
|
||||||
|
}, "Attribute values should not be parsed.")
|
||||||
|
test(function() {
|
||||||
|
var el = document.getElementsByTagName("span")[0]
|
||||||
|
attr_is(el.attributes[0], "test1", "id", null, null, "id")
|
||||||
|
}, "Specified attributes should be accessible.")
|
||||||
|
test(function() {
|
||||||
|
var el = document.getElementsByTagName("span")[1]
|
||||||
|
attr_is(el.attributes[0], "&<>foo", "class", null, null, "class")
|
||||||
|
}, "Entities in attributes should have been expanded while parsing.")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
assert_equals(el.hasAttribute("bar"), false)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "bar"), false)
|
||||||
|
assert_equals(el.hasAttributeNS("", "bar"), false)
|
||||||
|
assert_equals(el.getAttribute("bar"), null)
|
||||||
|
assert_equals(el.getAttributeNS(null, "bar"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "bar"), null)
|
||||||
|
}, "Unset attributes return null")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttributeNS("ab", "attr", "t1")
|
||||||
|
el.setAttributeNS("kl", "attr", "t2")
|
||||||
|
assert_equals(el.hasAttribute("attr"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("ab", "attr"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("kl", "attr"), true)
|
||||||
|
assert_equals(el.getAttribute("attr"), "t1")
|
||||||
|
assert_equals(el.getAttributeNS("ab", "attr"), "t1")
|
||||||
|
assert_equals(el.getAttributeNS("kl", "attr"), "t2")
|
||||||
|
assert_equals(el.getAttributeNS(null, "attr"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "attr"), null)
|
||||||
|
}, "First set attribute is returned by getAttribute")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("style", "color:#fff;")
|
||||||
|
assert_equals(el.hasAttribute("style"), true)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "style"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("", "style"), true)
|
||||||
|
assert_equals(el.getAttribute("style"), "color:#fff;")
|
||||||
|
assert_equals(el.getAttributeNS(null, "style"), "color:#fff;")
|
||||||
|
assert_equals(el.getAttributeNS("", "style"), "color:#fff;")
|
||||||
|
}, "Style attributes are not normalized")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttributeNS("", "ALIGN", "left")
|
||||||
|
assert_equals(el.hasAttribute("ALIGN"), false)
|
||||||
|
assert_equals(el.hasAttribute("align"), false)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "ALIGN"), true)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "align"), false)
|
||||||
|
assert_equals(el.hasAttributeNS("", "ALIGN"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("", "align"), false)
|
||||||
|
assert_equals(el.getAttribute("ALIGN"), null)
|
||||||
|
assert_equals(el.getAttribute("align"), null)
|
||||||
|
assert_equals(el.getAttributeNS(null, "ALIGN"), "left")
|
||||||
|
assert_equals(el.getAttributeNS("", "ALIGN"), "left")
|
||||||
|
assert_equals(el.getAttributeNS(null, "align"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "align"), null)
|
||||||
|
el.removeAttributeNS("", "ALIGN")
|
||||||
|
}, "Only lowercase attributes are returned on HTML elements (upper case attribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttributeNS("", "CHEEseCaKe", "tasty")
|
||||||
|
assert_equals(el.hasAttribute("CHEESECAKE"), false)
|
||||||
|
assert_equals(el.hasAttribute("CHEEseCaKe"), false)
|
||||||
|
assert_equals(el.hasAttribute("cheesecake"), false)
|
||||||
|
assert_equals(el.hasAttributeNS("", "CHEESECAKE"), false)
|
||||||
|
assert_equals(el.hasAttributeNS("", "CHEEseCaKe"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("", "cheesecake"), false)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "CHEESECAKE"), false)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "CHEEseCaKe"), true)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "cheesecake"), false)
|
||||||
|
assert_equals(el.getAttribute("CHEESECAKE"), null)
|
||||||
|
assert_equals(el.getAttribute("CHEEseCaKe"), null)
|
||||||
|
assert_equals(el.getAttribute("cheesecake"), null)
|
||||||
|
assert_equals(el.getAttributeNS(null, "CHEESECAKE"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "CHEESECAKE"), null)
|
||||||
|
assert_equals(el.getAttributeNS(null, "CHEEseCaKe"), "tasty")
|
||||||
|
assert_equals(el.getAttributeNS("", "CHEEseCaKe"), "tasty")
|
||||||
|
assert_equals(el.getAttributeNS(null, "cheesecake"), null)
|
||||||
|
assert_equals(el.getAttributeNS("", "cheesecake"), null)
|
||||||
|
el.removeAttributeNS("", "CHEEseCaKe")
|
||||||
|
}, "Only lowercase attributes are returned on HTML elements (mixed case attribute)")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
document.body.appendChild(el)
|
||||||
|
el.setAttributeNS("", "align", "left")
|
||||||
|
el.setAttributeNS("xx", "align", "right")
|
||||||
|
el.setAttributeNS("", "foo", "left")
|
||||||
|
el.setAttributeNS("xx", "foo", "right")
|
||||||
|
assert_equals(el.hasAttribute("align"), true)
|
||||||
|
assert_equals(el.hasAttribute("foo"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("xx", "align"), true)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "foo"), true)
|
||||||
|
assert_equals(el.getAttribute("align"), "left")
|
||||||
|
assert_equals(el.getAttribute("foo"), "left")
|
||||||
|
assert_equals(el.getAttributeNS("xx", "align"), "right")
|
||||||
|
assert_equals(el.getAttributeNS(null, "foo"), "left")
|
||||||
|
assert_equals(el.getAttributeNS("", "foo"), "left")
|
||||||
|
el.removeAttributeNS("", "align")
|
||||||
|
el.removeAttributeNS("xx", "align")
|
||||||
|
el.removeAttributeNS("", "foo")
|
||||||
|
el.removeAttributeNS("xx", "foo")
|
||||||
|
document.body.removeChild(el)
|
||||||
|
}, "First set attribute is returned with mapped attribute set first")
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttributeNS("xx", "align", "right")
|
||||||
|
el.setAttributeNS("", "align", "left")
|
||||||
|
el.setAttributeNS("xx", "foo", "right")
|
||||||
|
el.setAttributeNS("", "foo", "left")
|
||||||
|
assert_equals(el.hasAttribute("align"), true)
|
||||||
|
assert_equals(el.hasAttribute("foo"), true)
|
||||||
|
assert_equals(el.hasAttributeNS("xx", "align"), true)
|
||||||
|
assert_equals(el.hasAttributeNS(null, "foo"), true)
|
||||||
|
assert_equals(el.getAttribute("align"), "right")
|
||||||
|
assert_equals(el.getAttribute("foo"), "right")
|
||||||
|
assert_equals(el.getAttributeNS("xx", "align"), "right")
|
||||||
|
assert_equals(el.getAttributeNS(null, "foo"), "left")
|
||||||
|
assert_equals(el.getAttributeNS("", "foo"), "left")
|
||||||
|
el.removeAttributeNS("", "align")
|
||||||
|
el.removeAttributeNS("xx", "align")
|
||||||
|
el.removeAttributeNS("", "foo")
|
||||||
|
el.removeAttributeNS("xx", "foo")
|
||||||
|
}, "First set attribute is returned with mapped attribute set later")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElementNS("http://www.example.com", "foo")
|
||||||
|
el.setAttribute("A", "test")
|
||||||
|
assert_equals(el.hasAttribute("A"), true, "hasAttribute()")
|
||||||
|
assert_equals(el.hasAttributeNS("", "A"), true, "el.hasAttributeNS(\"\")")
|
||||||
|
assert_equals(el.hasAttributeNS(null, "A"), true, "el.hasAttributeNS(null)")
|
||||||
|
assert_equals(el.hasAttributeNS(undefined, "A"), true, "el.hasAttributeNS(undefined)")
|
||||||
|
assert_equals(el.hasAttributeNS("foo", "A"), false, "el.hasAttributeNS(\"foo\")")
|
||||||
|
|
||||||
|
assert_equals(el.getAttribute("A"), "test", "getAttribute()")
|
||||||
|
assert_equals(el.getAttributeNS("", "A"), "test", "el.getAttributeNS(\"\")")
|
||||||
|
assert_equals(el.getAttributeNS(null, "A"), "test", "el.getAttributeNS(null)")
|
||||||
|
assert_equals(el.getAttributeNS(undefined, "A"), "test", "el.getAttributeNS(undefined)")
|
||||||
|
assert_equals(el.getAttributeNS("foo", "A"), null, "el.getAttributeNS(\"foo\")")
|
||||||
|
}, "Non-HTML element with upper-case attribute")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("pre:fix", "value 1")
|
||||||
|
el.setAttribute("fix", "value 2")
|
||||||
|
|
||||||
|
var prefixed = el.attributes[0]
|
||||||
|
assert_equals(prefixed.localName, "pre:fix", "prefixed local name")
|
||||||
|
assert_equals(prefixed.namespaceURI, null, "prefixed namespace")
|
||||||
|
|
||||||
|
var unprefixed = el.attributes[1]
|
||||||
|
assert_equals(unprefixed.localName, "fix", "unprefixed local name")
|
||||||
|
assert_equals(unprefixed.namespaceURI, null, "unprefixed namespace")
|
||||||
|
|
||||||
|
el.removeAttributeNS(null, "pre:fix")
|
||||||
|
assert_equals(el.attributes[0], unprefixed)
|
||||||
|
}, "Attribute with prefix in local name")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("foo", "bar")
|
||||||
|
var attr = el.attributes[0]
|
||||||
|
assert_equals(attr.ownerElement, el)
|
||||||
|
el.removeAttribute("foo")
|
||||||
|
assert_equals(attr.ownerElement, null)
|
||||||
|
}, "Attribute loses its owner when removed")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("foo", "bar")
|
||||||
|
var attr = el.attributes[0]
|
||||||
|
var attrNode = el.getAttributeNode("foo");
|
||||||
|
var attrNodeNS = el.getAttributeNodeNS("", "foo");
|
||||||
|
assert_equals(attr, attrNode);
|
||||||
|
assert_equals(attr, attrNodeNS);
|
||||||
|
el.setAttributeNS("x", "foo2", "bar2");
|
||||||
|
var attr2 = el.attributes[1];
|
||||||
|
var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2");
|
||||||
|
assert_equals(attr2, attrNodeNS2);
|
||||||
|
}, "Basic functionality of getAttributeNode/getAttributeNodeNS")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("foo", "bar")
|
||||||
|
var attrNode = el.getAttributeNode("foo");
|
||||||
|
var attrNodeNS = el.getAttributeNodeNS("", "foo");
|
||||||
|
assert_equals(attrNode, attrNodeNS);
|
||||||
|
el.removeAttribute("foo");
|
||||||
|
var el2 = document.createElement("div");
|
||||||
|
el2.setAttributeNode(attrNode);
|
||||||
|
assert_equals(attrNode, el2.getAttributeNode("foo"));
|
||||||
|
assert_equals(attrNode, el2.attributes[0]);
|
||||||
|
assert_equals(attrNode.ownerElement, el2);
|
||||||
|
assert_equals(attrNode.value, "bar");
|
||||||
|
|
||||||
|
var el3 = document.createElement("div");
|
||||||
|
el2.removeAttribute("foo");
|
||||||
|
el3.setAttribute("foo", "baz");
|
||||||
|
el3.setAttributeNode(attrNode);
|
||||||
|
assert_equals(el3.getAttribute("foo"), "bar");
|
||||||
|
}, "Basic functionality of setAttributeNode")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
var attr1 = document.createAttributeNS("ns1", "p1:name");
|
||||||
|
attr1.value = "value1";
|
||||||
|
var attr2 = document.createAttributeNS("ns2", "p2:name");
|
||||||
|
attr2.value = "value2";
|
||||||
|
el.setAttributeNode(attr1);
|
||||||
|
el.setAttributeNode(attr2);
|
||||||
|
assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1");
|
||||||
|
assert_equals(el.getAttributeNodeNS("ns2", "name").value, "value2");
|
||||||
|
}, "setAttributeNode should distinguish attributes with same local name and different namespaces")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
var attr1 = document.createAttributeNS("ns1", "p1:name");
|
||||||
|
attr1.value = "value1";
|
||||||
|
var attr2 = document.createAttributeNS("ns1", "p1:NAME");
|
||||||
|
attr2.value = "VALUE2";
|
||||||
|
el.setAttributeNode(attr1);
|
||||||
|
el.setAttributeNode(attr2);
|
||||||
|
assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1");
|
||||||
|
assert_equals(el.getAttributeNodeNS("ns1", "NAME").value, "VALUE2");
|
||||||
|
}, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttributeNS("x", "foo", "bar")
|
||||||
|
var attrNode = el.getAttributeNodeNS("x", "foo");
|
||||||
|
el.removeAttribute("foo");
|
||||||
|
var el2 = document.createElement("div");
|
||||||
|
el2.setAttributeNS("x", "foo", "baz");
|
||||||
|
el2.setAttributeNodeNS(attrNode);
|
||||||
|
assert_equals(el2.getAttributeNS("x", "foo"), "bar");
|
||||||
|
}, "Basic functionality of setAttributeNodeNS")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
var other = document.createElement("div");
|
||||||
|
var attr = document.createAttribute("foo");
|
||||||
|
assert_equals(el.setAttributeNode(attr), null);
|
||||||
|
assert_equals(attr.ownerElement, el);
|
||||||
|
assert_throws_dom("INUSE_ATTRIBUTE_ERR",
|
||||||
|
function() { other.setAttributeNode(attr) },
|
||||||
|
"Attribute already associated with el")
|
||||||
|
}, "If attr’s element is neither null nor element, throw an InUseAttributeError.");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
var attr = document.createAttribute("foo");
|
||||||
|
assert_equals(el.setAttributeNode(attr), null);
|
||||||
|
el.setAttribute("bar", "qux");
|
||||||
|
assert_equals(el.setAttributeNode(attr), attr);
|
||||||
|
assert_equals(el.attributes[0], attr);
|
||||||
|
}, "Replacing an attr by itself");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("foo", "bar")
|
||||||
|
var attrNode = el.getAttributeNode("foo");
|
||||||
|
el.removeAttributeNode(attrNode);
|
||||||
|
var el2 = document.createElement("div");
|
||||||
|
el2.setAttributeNode(attrNode);
|
||||||
|
assert_equals(el2.attributes[0], attrNode);
|
||||||
|
assert_equals(el.attributes.length, 0);
|
||||||
|
}, "Basic functionality of removeAttributeNode")
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("foo", "bar")
|
||||||
|
var attrNode = el.getAttributeNode("foo");
|
||||||
|
var el2 = document.createElement("div");
|
||||||
|
assert_throws_dom("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)});
|
||||||
|
}, "setAttributeNode on bound attribute should throw InUseAttributeError")
|
||||||
|
|
||||||
|
// Have to use an async_test to see what a DOMAttrModified listener sees,
|
||||||
|
// because otherwise the event dispatch code will swallow our exceptions. And
|
||||||
|
// we want to make sure this test always happens, even when no mutation events
|
||||||
|
// run.
|
||||||
|
var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
var el = document.createElement("div")
|
||||||
|
var attrNode1 = document.createAttribute("foo");
|
||||||
|
attrNode1.value = "bar";
|
||||||
|
el.setAttributeNode(attrNode1);
|
||||||
|
var attrNode2 = document.createAttribute("foo");
|
||||||
|
attrNode2.value = "baz";
|
||||||
|
|
||||||
|
el.addEventListener("DOMAttrModified", function(e) {
|
||||||
|
// If this never gets called, that's OK, I guess. But if it gets called, it
|
||||||
|
// better represent a single modification with attrNode2 as the relatedNode.
|
||||||
|
// We have to do an inner test() call here, because otherwise the exceptions
|
||||||
|
// our asserts trigger will get swallowed by the event dispatch code.
|
||||||
|
setAttributeNode_mutation_test.step(function() {
|
||||||
|
assert_equals(e.attrName, "foo");
|
||||||
|
assert_equals(e.attrChange, MutationEvent.MODIFICATION);
|
||||||
|
assert_equals(e.prevValue, "bar");
|
||||||
|
assert_equals(e.newValue, "baz");
|
||||||
|
assert_equals(e.relatedNode, attrNode2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var oldNode = el.setAttributeNode(attrNode2);
|
||||||
|
assert_equals(oldNode, attrNode1,
|
||||||
|
"Must return the old attr node from a setAttributeNode call");
|
||||||
|
}, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)");
|
||||||
|
setAttributeNode_mutation_test.done();
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
var el = document.createElement("div")
|
||||||
|
el.setAttribute("a", "b");
|
||||||
|
el.setAttribute("c", "d");
|
||||||
|
|
||||||
|
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
|
||||||
|
["a", "c"]);
|
||||||
|
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
|
||||||
|
["b", "d"]);
|
||||||
|
|
||||||
|
var attrNode = document.createAttribute("a");
|
||||||
|
attrNode.value = "e";
|
||||||
|
el.setAttributeNode(attrNode);
|
||||||
|
|
||||||
|
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
|
||||||
|
["a", "c"]);
|
||||||
|
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
|
||||||
|
["e", "d"]);
|
||||||
|
}, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttribute("foo", "bar");
|
||||||
|
assert_equals(el.getAttributeNames().length, 1);
|
||||||
|
assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
|
||||||
|
assert_equals(el.getAttributeNames()[0], "foo");
|
||||||
|
|
||||||
|
el.removeAttribute("foo");
|
||||||
|
assert_equals(el.getAttributeNames().length, 0);
|
||||||
|
|
||||||
|
el.setAttribute("foo", "bar");
|
||||||
|
el.setAttributeNS("", "FOO", "bar");
|
||||||
|
el.setAttributeNS("dummy1", "foo", "bar");
|
||||||
|
el.setAttributeNS("dummy2", "dummy:foo", "bar");
|
||||||
|
assert_equals(el.getAttributeNames().length, 4);
|
||||||
|
assert_equals(el.getAttributeNames()[0], "foo");
|
||||||
|
assert_equals(el.getAttributeNames()[1], "FOO");
|
||||||
|
assert_equals(el.getAttributeNames()[2], "foo");
|
||||||
|
assert_equals(el.getAttributeNames()[3], "dummy:foo");
|
||||||
|
assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
|
||||||
|
assert_equals(el.getAttributeNames()[1], el.attributes[1].name);
|
||||||
|
assert_equals(el.getAttributeNames()[2], el.attributes[2].name);
|
||||||
|
assert_equals(el.getAttributeNames()[3], el.attributes[3].name);
|
||||||
|
|
||||||
|
el.removeAttributeNS("", "FOO");
|
||||||
|
assert_equals(el.getAttributeNames().length, 3);
|
||||||
|
assert_equals(el.getAttributeNames()[0], "foo");
|
||||||
|
assert_equals(el.getAttributeNames()[1], "foo");
|
||||||
|
assert_equals(el.getAttributeNames()[2], "dummy:foo");
|
||||||
|
assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
|
||||||
|
assert_equals(el.getAttributeNames()[1], el.attributes[1].name);
|
||||||
|
assert_equals(el.getAttributeNames()[2], el.attributes[2].name);
|
||||||
|
}, "getAttributeNames tests");
|
||||||
|
|
||||||
|
function getEnumerableOwnProps1(obj) {
|
||||||
|
var arr = [];
|
||||||
|
for (var prop in obj) {
|
||||||
|
if (obj.hasOwnProperty(prop)) {
|
||||||
|
arr.push(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnumerableOwnProps2(obj) {
|
||||||
|
return Object.getOwnPropertyNames(obj).filter(
|
||||||
|
function (name) { return Object.getOwnPropertyDescriptor(obj, name).enumerable; })
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttribute("a", "");
|
||||||
|
el.setAttribute("b", "");
|
||||||
|
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||||
|
["0", "1"])
|
||||||
|
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||||
|
["0", "1"])
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "a", "b"])
|
||||||
|
}, "Own property correctness with basic attributes");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttributeNS("", "a", "");
|
||||||
|
el.setAttribute("b", "");
|
||||||
|
el.setAttributeNS("foo", "a", "");
|
||||||
|
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "a", "b"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property correctness with non-namespaced attribute before same-name namespaced one");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttributeNS("foo", "a", "");
|
||||||
|
el.setAttribute("b", "");
|
||||||
|
el.setAttributeNS("", "a", "");
|
||||||
|
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "a", "b"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property correctness with namespaced attribute before same-name non-namespaced one");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttributeNS("foo", "a:b", "");
|
||||||
|
el.setAttributeNS("foo", "c:d", "");
|
||||||
|
el.setAttributeNS("bar", "a:b", "");
|
||||||
|
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||||
|
["0", "1", "2"])
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "a:b", "c:d"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property correctness with two namespaced attributes with the same name-with-prefix");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.setAttributeNS("foo", "A:B", "");
|
||||||
|
el.setAttributeNS("bar", "c:D", "");
|
||||||
|
el.setAttributeNS("baz", "e:F", "");
|
||||||
|
el.setAttributeNS("qux", "g:h", "");
|
||||||
|
el.setAttributeNS("", "I", "");
|
||||||
|
el.setAttributeNS("", "j", "");
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "3", "4", "5", "g:h", "j"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var el = document.createElementNS("", "div");
|
||||||
|
el.setAttributeNS("foo", "A:B", "");
|
||||||
|
el.setAttributeNS("bar", "c:D", "");
|
||||||
|
el.setAttributeNS("baz", "e:F", "");
|
||||||
|
el.setAttributeNS("qux", "g:h", "");
|
||||||
|
el.setAttributeNS("", "I", "");
|
||||||
|
el.setAttributeNS("", "j", "");
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property names should include all qualified names for a non-HTML element in an HTML document");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var doc = document.implementation.createDocument(null, "");
|
||||||
|
assert_equals(doc.contentType, "application/xml");
|
||||||
|
var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||||
|
el.setAttributeNS("foo", "A:B", "");
|
||||||
|
el.setAttributeNS("bar", "c:D", "");
|
||||||
|
el.setAttributeNS("baz", "e:F", "");
|
||||||
|
el.setAttributeNS("qux", "g:h", "");
|
||||||
|
el.setAttributeNS("", "I", "");
|
||||||
|
el.setAttributeNS("", "j", "");
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||||
|
["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
|
||||||
|
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||||
|
assert_true(el.attributes[propName] instanceof Attr,
|
||||||
|
"el.attributes has an Attr for property name " + propName);
|
||||||
|
}
|
||||||
|
}, "Own property names should include all qualified names for an HTML element in a non-HTML document");
|
||||||
|
</script>
|
||||||
18
tests/wpt/dom/nodes/attributes.js
Normal file
18
tests/wpt/dom/nodes/attributes.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
function attr_is(attr, v, ln, ns, p, n) {
|
||||||
|
assert_equals(attr.value, v)
|
||||||
|
assert_equals(attr.nodeValue, v)
|
||||||
|
assert_equals(attr.textContent, v)
|
||||||
|
assert_equals(attr.localName, ln)
|
||||||
|
assert_equals(attr.namespaceURI, ns)
|
||||||
|
assert_equals(attr.prefix, p)
|
||||||
|
assert_equals(attr.name, n)
|
||||||
|
assert_equals(attr.nodeName, n);
|
||||||
|
assert_equals(attr.specified, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function attributes_are(el, l) {
|
||||||
|
for (var i = 0, il = l.length; i < il; i++) {
|
||||||
|
attr_is(el.attributes[i], l[i][1], l[i][0], (l[i].length < 3) ? null : l[i][2], null, l[i][0])
|
||||||
|
assert_equals(el.attributes[i].ownerElement, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
tests/wpt/dom/nodes/productions.js
Normal file
3
tests/wpt/dom/nodes/productions.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var invalid_names = ["", "invalid^Name", "\\", "'", '"', "0", "0:a"] // XXX
|
||||||
|
var valid_names = ["x", "X", ":", "a:0"]
|
||||||
|
var invalid_qnames = [":a", "b:", "x:y:z"] // XXX
|
||||||
Reference in New Issue
Block a user