diff options
Diffstat (limited to 'dom/base/test/test_classList.html')
-rw-r--r-- | dom/base/test/test_classList.html | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/dom/base/test/test_classList.html b/dom/base/test/test_classList.html new file mode 100644 index 000000000..2a108d7f5 --- /dev/null +++ b/dom/base/test/test_classList.html @@ -0,0 +1,426 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=501257 +--> +<head> + <title>Test for the classList element attribute</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="http://www.whatwg.org/specs/web-apps/current-work/#dom-classlist">classList DOM attribute</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 501257 **/ + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const SVG_NS = "http://www.w3.org/2000/svg"; +const XHTML_NS = "http://www.w3.org/1999/xhtml" +const MATHML_NS = "http://www.w3.org/1998/Math/MathML"; + +var gMutationEvents = []; + +function onAttrModified(event) { + is(event.attrName, "class", "mutation on unexpected attribute"); + + gMutationEvents.push({ + attrChange: event.attrChange, + prevValue: event.prevValue, + newValue: event.newValue, + }); +} + +function checkModification(e, funcName, args, expectedRes, before, after, expectedException) { + if (!Array.isArray(args)) { + args = [args]; + } + + var shouldThrow = typeof(expectedException) === "string"; + if (shouldThrow) { + // If an exception is thrown, the class attribute shouldn't change. + after = before; + } + if (before === null) + e.removeAttribute("class"); + else + e.setAttribute("class", before); + + var contextMsg = "(checkModification: funcName=" + funcName + ",args=" + + JSON.stringify(args) + ",expectedRes=" + expectedRes + + ",before=" + before + ",after=" + after + ")"; + + gMutationEvents = []; + e.addEventListener("DOMAttrModified", onAttrModified, false); + try { + var list = e.classList; + var res = list[funcName].apply(list, args); + if (shouldThrow) + ok(false, "classList modification didn't throw " + contextMsg); + } catch (e) { + if (!shouldThrow) + ok(false, "classList modification threw an exception " + contextMsg); + is(e.name, expectedException, "wrong exception thrown " + contextMsg); + } + e.removeEventListener("DOMAttrModified", onAttrModified, false); + if (expectedRes !== null) + is(res, expectedRes, "wrong return value from " + funcName + + " " + contextMsg); + + var expectedAfter = after; + // XUL returns an empty string when getting a nonexistent class attribute. + if (e.namespaceURI == XUL_NS && expectedAfter === null) + expectedAfter = ""; + + is(e.getAttribute("class"), expectedAfter, "wrong class after modification " + + contextMsg); + var expectedMutation = before != after; + is(gMutationEvents.length, expectedMutation ? 1 : 0, + "unexpected mutation event count " + contextMsg); + if (expectedMutation && gMutationEvents.length) { + is(gMutationEvents[0].attrChange, + before == null ? MutationEvent.ADDITION : MutationEvent.MODIFICATION, + "wrong type of attribute change " + contextMsg); + // If there wasn't any previous attribute, prevValue will return an empty + // string. + var expectedPrevValue = before === null ? "" : before; + is(gMutationEvents[0].prevValue, expectedPrevValue, + "wrong previous value " + contextMsg); + is(gMutationEvents[0].newValue, after, "wrong new value " + contextMsg); + } +} + +function assignToClassListStrict(e) { + "use strict"; + try { + e.classList = "foo"; + ok(true, "assigning to classList didn't throw"); + e.removeAttribute("class"); + } catch (e) { + ok(false, "assigning to classList threw"); + } +} + +function assignToClassList(e) { + try { + var expect = e.classList; + e.classList = "foo"; + ok(true, "assigning to classList didn't throw"); + is(e.classList, expect, "classList should be unchanged after assignment"); + e.removeAttribute("class"); + } catch (e) { + ok(false, "assigning to classList threw"); + } +} + +function testClassList(e) { + + // basic tests + + isnot(e.classList, undefined, "no classList attribute"); + is(typeof(e.classList.contains), "function", + "no classList.contains function"); + is(typeof(e.classList.add), "function", "no classList.add function"); + is(typeof(e.classList.remove), "function", "no classList.remove function"); + is(typeof(e.classList.toggle), "function", "no classList.toggle function"); + + assignToClassListStrict(e); + assignToClassList(e); + + // length attribute + + is(e.classList.length, 0, "wrong classList.length value"); + e.setAttribute("class", ""); + is(e.classList.length, 0, "wrong classList.length value"); + e.setAttribute("class", " \t \f"); + is(e.classList.length, 0, "wrong classList.length value"); + + e.setAttribute("class", "a"); + is(e.classList.length, 1, "wrong classList.length value"); + e.setAttribute("class", "a A"); + is(e.classList.length, 2, "wrong classList.length value"); + e.setAttribute("class", "\r\na\t\f"); + is(e.classList.length, 1, "wrong classList.length value"); + + e.setAttribute("class", "a a"); + is(e.classList.length, 2, "wrong classList.length value"); + + e.setAttribute("class", "a a a a a a"); + is(e.classList.length, 6, "wrong classList.length value"); + + e.setAttribute("class", "a a b b"); + is(e.classList.length, 4, "wrong classList.length value"); + + e.setAttribute("class", "a A B b"); + is(e.classList.length, 4, "wrong classList.length value"); + + e.setAttribute("class", "a b c c b a a b c c"); + is(e.classList.length, 10, "wrong classList.length value"); + + // [Stringifies] + + ok(DOMTokenList.prototype.hasOwnProperty("toString"), + "Should have own toString on DOMTokenList") + + e.removeAttribute("class"); + is(e.classList.toString(), "", "wrong classList.toString() value"); + is(e.classList + "", "", "wrong classList string conversion value"); + + e.setAttribute("class", "foo"); + is(e.classList.toString(), "foo", "wrong classList.toString() value"); + is(e.classList + "", "foo", "wrong classList string conversion value"); + + // item() method + + e.setAttribute("class", "a"); + is(e.classList.item(-1), null, "wrong classList.item() result"); + is(e.classList[-1], undefined, "wrong classList[] result"); + is(e.classList.item(0), "a", "wrong classList.item() result"); + is(e.classList[0], "a", "wrong classList[] result"); + is(e.classList.item(1), null, "wrong classList.item() result"); + is(e.classList[1], undefined, "wrong classList[] result"); + + e.setAttribute("class", "aa AA aa"); + is(e.classList.item(-1), null, "wrong classList.item() result"); + is(e.classList[-1], undefined, "wrong classList[] result"); + is(e.classList.item(0), "aa", "wrong classList.item() result"); + is(e.classList[0], "aa", "wrong classList[] result"); + is(e.classList.item(1), "AA", "wrong classList.item() result"); + is(e.classList[1], "AA", "wrong classList[] result"); + is(e.classList.item(2), "aa", "wrong classList.item() result"); + is(e.classList[2], "aa", "wrong classList[] result"); + is(e.classList.item(3), null, "wrong classList.item() result"); + is(e.classList[3], undefined, "wrong classList[] result"); + is(e.classList.item(0xffffffff), null, "wrong classList.item() result"); + is(e.classList[0xffffffff], undefined, "wrong classList[] result"); + is(e.classList.item(0xfffffffe), null, "wrong classList.item() result"); + is(e.classList[0xffffffe], undefined, "wrong classList[] result"); + + e.setAttribute("class", "a b"); + is(e.classList.item(-1), null, "wrong classList.item() result"); + is(e.classList[-1], undefined, "wrong classList[] result"); + is(e.classList.item(0), "a", "wrong classList.item() result"); + is(e.classList[0], "a", "wrong classList[] result"); + is(e.classList.item(1), "b", "wrong classList.item() result"); + is(e.classList[1], "b", "wrong classList[] result"); + is(e.classList.item(2), null, "wrong classList.item() result"); + is(e.classList[2], undefined, "wrong classList[] result"); + + // contains() method + + e.removeAttribute("class"); + is(e.classList.contains("a"), false, "wrong classList.contains() result"); + try { + e.classList.contains(""); + ok(true, "classList.contains(empty_string) didn't throw"); + } catch (e) { + ok(false, "classList.contains(empty_string) threw"); + } + try { + e.classList.contains(" "); + ok(true, "classList.contains(string_with_spaces) didn't throw"); + } catch (e) { + ok(false, "classList.contains(string_with_spaces) threw"); + } + try { + e.classList.contains("aa "); + ok(true, "classList.contains(string_with_spaces) didn't throw"); + } catch (e) { + ok(false, "classList.contains(string_with_spaces) threw"); + } + + e.setAttribute("class", ""); + is(e.classList.contains("a"), false, "wrong classList.contains() result"); + + e.setAttribute("class", "a"); + is(e.classList.contains("a"), true, "wrong classList.contains() result"); + is(e.classList.contains("aa"), false, "wrong classList.contains() result"); + is(e.classList.contains("b"), false, "wrong classList.contains() result"); + + e.setAttribute("class", "aa AA"); + is(e.classList.contains("aa"), true, "wrong classList.contains() result"); + is(e.classList.contains("AA"), true, "wrong classList.contains() result"); + is(e.classList.contains("aA"), false, "wrong classList.contains() result"); + + e.setAttribute("class", "a a a"); + is(e.classList.contains("a"), true, "wrong classList.contains() result"); + is(e.classList.contains("aa"), false, "wrong classList.contains() result"); + is(e.classList.contains("b"), false, "wrong classList.contains() result"); + + e.setAttribute("class", "a b c"); + is(e.classList.contains("a"), true, "wrong classList.contains() result"); + is(e.classList.contains("b"), true, "wrong classList.contains() result"); + + // Test for bug 530171 + e.setAttribute("class", "null undefined"); + is(e.classList.contains(null), true, "wrong classList.contains() result"); + is(e.classList.contains(undefined), true, "wrong classList.contains() result"); + + // add() method + + function checkAdd(before, argument, after, expectedException) { + checkModification(e, "add", argument, null, before, after, expectedException); + } + + checkAdd(null, "", null, "SyntaxError"); + checkAdd(null, ["a", ""], null, "SyntaxError"); + checkAdd(null, " ", null, "InvalidCharacterError"); + checkAdd(null, ["a", " "], null, "InvalidCharacterError"); + checkAdd(null, ["a", "aa "], null, "InvalidCharacterError"); + + checkAdd("a", "a", "a"); + checkAdd("aa", "AA", "aa AA"); + checkAdd("a b c", "a", "a b c"); + checkAdd("a a a b", "a", "a a a b"); + checkAdd(null, "a", "a"); + checkAdd("", "a", "a"); + checkAdd(" ", "a", " a"); + checkAdd(" \f", "a", " \fa"); + checkAdd("a", "b", "a b"); + checkAdd("a b c", "d", "a b c d"); + checkAdd("a b c ", "d", "a b c d"); + + // multiple add + checkAdd("a b c ", ["d", "e"], "a b c d e"); + checkAdd("a b c ", ["a", "a"], "a b c "); + checkAdd("a b c ", ["d", "d"], "a b c d"); + checkAdd("a b c ", [], "a b c "); + checkAdd(null, ["a", "b"], "a b"); + checkAdd("", ["a", "b"], "a b"); + + // Test for bug 530171 + checkAdd(null, null, "null"); + checkAdd(null, undefined, "undefined"); + + // remove() method + + function checkRemove(before, argument, after, expectedException) { + checkModification(e, "remove", argument, null, before, after, expectedException); + } + + checkRemove(null, "", null, "SyntaxError"); + checkRemove(null, " ", null, "InvalidCharacterError"); + checkRemove(null, "aa ", null, "InvalidCharacterError"); + + checkRemove(null, "a", null); + checkRemove("", "a", ""); + checkRemove("a b c", "d", "a b c"); + checkRemove("a b c", "A", "a b c"); + checkRemove(" a a a ", "a", ""); + checkRemove("a b", "a", "b"); + checkRemove("a b ", "a", "b"); + checkRemove("a a b", "a", "b"); + checkRemove("aa aa bb", "aa", "bb"); + checkRemove("a a b a a c a a", "a", "b c"); + + checkRemove("a b c", "b", "a c"); + checkRemove("aaa bbb ccc", "bbb", "aaa ccc"); + checkRemove(" a b c ", "b", "a c"); + checkRemove("a b b b c", "b", "a c"); + + checkRemove("a b c", "c", "a b"); + checkRemove(" a b c ", "c", "a b"); + checkRemove("a b c c c", "c", "a b"); + + checkRemove("a b a c a d a", "a", "b c d"); + checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd aa"); + + checkRemove("\ra\na\ta\f", "a", ""); + + // multiple remove + checkRemove("a b c ", ["d", "e"], "a b c"); + checkRemove("a b c ", ["a", "b"], "c"); + checkRemove("a b c ", ["a", "c"], "b"); + checkRemove("a b c ", ["a", "a"], "b c"); + checkRemove("a b c ", ["d", "d"], "a b c"); + checkRemove("a b c ", [], "a b c"); + checkRemove(null, ["a", "b"], null); + checkRemove("", ["a", "b"], ""); + + // Test for bug 530171 + checkRemove("null", null, ""); + checkRemove("undefined", undefined, ""); + + // toggle() method + + function checkToggle(before, argument, expectedRes, after, expectedException) { + checkModification(e, "toggle", argument, expectedRes, before, after, expectedException); + } + + checkToggle(null, "", null, null, "SyntaxError"); + checkToggle(null, "aa ", null, null, "InvalidCharacterError"); + + checkToggle(null, "a", true, "a"); + checkToggle("", "a", true, "a"); + checkToggle(" ", "a", true, " a"); + checkToggle(" \f", "a", true, " \fa"); + checkToggle("a", "b", true, "a b"); + checkToggle("a", "A", true, "a A"); + checkToggle("a b c", "d", true, "a b c d"); + checkToggle("a b c", "d", true, "a b c d"); + + checkToggle("a", "a", false, ""); + checkToggle(" a a a ", "a", false, ""); + checkToggle(" A A A ", "a", true, " A A A a"); + checkToggle(" a b c ", "b", false, "a c"); + checkToggle(" a b c b b", "b", false, "a c"); + checkToggle(" a b c ", "c", false, "a b"); + checkToggle(" a b c ", "a", false, "b c"); + + // Test for bug 530171 + checkToggle("null", null, false, ""); + checkToggle("", null, true, "null"); + checkToggle("undefined", undefined, false, ""); + checkToggle("", undefined, true, "undefined"); + + + // tests for the force argument handling + + function checkForceToggle(before, argument, force, expectedRes, after, expectedException) { + checkModification(e, "toggle", [argument, force], expectedRes, before, after, expectedException); + } + + checkForceToggle("", "a", true, true, "a"); + checkForceToggle("a", "a", true, true, "a"); + checkForceToggle("a", "b", true, true, "a b"); + checkForceToggle("a b", "b", true, true, "a b"); + checkForceToggle("", "a", false, false, ""); + checkForceToggle("a", "a", false, false, ""); + checkForceToggle("a", "b", false, false, "a"); + checkForceToggle("a b", "b", false, false, "a"); +} + +var content = document.getElementById("content"); + +var htmlNode = document.createElement("div"); +content.appendChild(htmlNode); +testClassList(htmlNode); + +var xhtmlNode = document.createElementNS(XHTML_NS, "div"); +content.appendChild(xhtmlNode); +testClassList(xhtmlNode); + +var xulNode = document.createElementNS(XUL_NS, "box"); +content.appendChild(xulNode); +testClassList(xulNode); + +var mathMLNode = document.createElementNS(MATHML_NS, "math"); +content.appendChild(mathMLNode); +testClassList(mathMLNode); + +var xmlNode = document.createElementNS(null, "foo"); +content.appendChild(xmlNode); +testClassList(xmlNode); + +var fooNode = document.createElementNS("http://example.org/foo", "foo"); +content.appendChild(fooNode); +testClassList(fooNode); + +</script> +</pre> +</body> +</html> |