| OLD | NEW |
| (Empty) |
| 1 /// Test for the Selectors API ported from | |
| 2 /// <https://github.com/w3c/web-platform-tests/tree/master/selectors-api> | |
| 3 /// | |
| 4 /// Note: tried to make minimal changes possible here. Hence some oddities such | |
| 5 /// as [test] arguments having a different order, long lines, etc. | |
| 6 /// | |
| 7 /// As usual with ports: being faithful to the original style is more important | |
| 8 /// than other style goals, as it reduces friction to integrating changes | |
| 9 /// from upstream. | |
| 10 library html5lib.test.selectors.level1_lib; | |
| 11 | |
| 12 import 'package:html5lib/dom.dart'; | |
| 13 import 'package:unittest/unittest.dart' as unittest; | |
| 14 | |
| 15 Document doc; | |
| 16 | |
| 17 /* | |
| 18 * Create and append special elements that cannot be created correctly with HTML
markup alone. | |
| 19 */ | |
| 20 setupSpecialElements(parent) { | |
| 21 // Setup null and undefined tests | |
| 22 parent.append(doc.createElement("null")); | |
| 23 parent.append(doc.createElement("undefined")); | |
| 24 | |
| 25 // Setup namespace tests | |
| 26 var anyNS = doc.createElement("div"); | |
| 27 var noNS = doc.createElement("div"); | |
| 28 anyNS.id = "any-namespace"; | |
| 29 noNS.id = "no-namespace"; | |
| 30 | |
| 31 var div; | |
| 32 div = [doc.createElement("div"), | |
| 33 doc.createElementNS("http://www.w3.org/1999/xhtml", "div"), | |
| 34 doc.createElementNS("", "div"), | |
| 35 doc.createElementNS("http://www.example.org/ns", "div")]; | |
| 36 | |
| 37 div[0].id = "any-namespace-div1"; | |
| 38 div[1].id = "any-namespace-div2"; | |
| 39 div[2].attributes["id"] = "any-namespace-div3"; // Non-HTML elements can't use
.id property | |
| 40 div[3].attributes["id"] = "any-namespace-div4"; | |
| 41 | |
| 42 for (var i = 0; i < div.length; i++) { | |
| 43 anyNS.append(div[i]); | |
| 44 } | |
| 45 | |
| 46 div = [doc.createElement("div"), | |
| 47 doc.createElementNS("http://www.w3.org/1999/xhtml", "div"), | |
| 48 doc.createElementNS("", "div"), | |
| 49 doc.createElementNS("http://www.example.org/ns", "div")]; | |
| 50 | |
| 51 div[0].id = "no-namespace-div1"; | |
| 52 div[1].id = "no-namespace-div2"; | |
| 53 div[2].attributes["id"] = "no-namespace-div3"; // Non-HTML elements can't use
.id property | |
| 54 div[3].attributes["id"] = "no-namespace-div4"; | |
| 55 | |
| 56 for (var i = 0; i < div.length; i++) { | |
| 57 noNS.append(div[i]); | |
| 58 } | |
| 59 | |
| 60 parent.append(anyNS); | |
| 61 parent.append(noNS); | |
| 62 } | |
| 63 | |
| 64 /* | |
| 65 * Check that the querySelector and querySelectorAll methods exist on the given
Node | |
| 66 */ | |
| 67 interfaceCheck(type, obj) { | |
| 68 test(() { | |
| 69 var q = obj.querySelector is Function; | |
| 70 assert_true(q, type + " supports querySelector."); | |
| 71 }, type + " supports querySelector"); | |
| 72 | |
| 73 test(() { | |
| 74 var qa = obj.querySelectorAll is Function; | |
| 75 assert_true( qa, type + " supports querySelectorAll."); | |
| 76 }, type + " supports querySelectorAll"); | |
| 77 | |
| 78 test(() { | |
| 79 var list = obj.querySelectorAll("div"); | |
| 80 // TODO(jmesserly): testing List<Element> for now. It should return an | |
| 81 // ElementList which has extra properties. Needed for dart:html compat. | |
| 82 assert_true(list is List<Element>, "The result should be an instance of a No
deList"); | |
| 83 }, type + ".querySelectorAll returns NodeList instance"); | |
| 84 } | |
| 85 | |
| 86 /* | |
| 87 * Verify that the NodeList returned by querySelectorAll is static and and that
a new list is created after | |
| 88 * each call. A static list should not be affected by subsequent changes to the
DOM. | |
| 89 */ | |
| 90 verifyStaticList(type, root) { | |
| 91 var pre, post, preLength; | |
| 92 | |
| 93 test(() { | |
| 94 pre = root.querySelectorAll("div"); | |
| 95 preLength = pre.length; | |
| 96 | |
| 97 var div = doc.createElement("div"); | |
| 98 (root is Document ? root.body : root).append(div); | |
| 99 | |
| 100 assert_equals(pre.length, preLength, "The length of the NodeList should not
change."); | |
| 101 }, type + ": static NodeList"); | |
| 102 | |
| 103 test(() { | |
| 104 post = root.querySelectorAll("div"); | |
| 105 assert_equals(post.length, preLength + 1, "The length of the new NodeList sh
ould be 1 more than the previous list."); | |
| 106 }, type + ": new NodeList"); | |
| 107 } | |
| 108 | |
| 109 /* | |
| 110 * Verify handling of special values for the selector parameter, including strin
gification of | |
| 111 * null and undefined, and the handling of the empty string. | |
| 112 */ | |
| 113 runSpecialSelectorTests(type, root) { | |
| 114 // Dart note: changed these tests because we don't have auto conversion to | |
| 115 // String like JavaScript does. | |
| 116 test(() { // 1 | |
| 117 assert_equals(root.querySelectorAll('null').length, 1, "This should find one
element with the tag name 'NULL'."); | |
| 118 }, type + ".querySelectorAll null"); | |
| 119 | |
| 120 test(() { // 2 | |
| 121 assert_equals(root.querySelectorAll('undefined').length, 1, "This should fin
d one element with the tag name 'UNDEFINED'."); | |
| 122 }, type + ".querySelectorAll undefined"); | |
| 123 | |
| 124 test(() { // 3 | |
| 125 assert_throws((e) => e is NoSuchMethodError, () { | |
| 126 root.querySelectorAll(); | |
| 127 }, "This should throw a TypeError."); | |
| 128 }, type + ".querySelectorAll no parameter"); | |
| 129 | |
| 130 test(() { // 4 | |
| 131 var elm = root.querySelector('null'); | |
| 132 assert_not_equals(elm, null, "This should find an element."); | |
| 133 // TODO(jmesserly): change "localName" back to "tagName" once implemented. | |
| 134 assert_equals(elm.localName.toUpperCase(), "NULL", "The tag name should be '
NULL'."); | |
| 135 }, type + ".querySelector null"); | |
| 136 | |
| 137 test(() { // 5 | |
| 138 var elm = root.querySelector('undefined'); | |
| 139 assert_not_equals(elm, 'undefined', "This should find an element."); | |
| 140 // TODO(jmesserly): change "localName" back to "tagName" once implemented. | |
| 141 assert_equals(elm.localName.toUpperCase(), "UNDEFINED", "The tag name should
be 'UNDEFINED'."); | |
| 142 }, type + ".querySelector undefined"); | |
| 143 | |
| 144 test(() { // 6 | |
| 145 assert_throws((e) => e is NoSuchMethodError, () { | |
| 146 root.querySelector(); | |
| 147 }, "This should throw a TypeError."); | |
| 148 }, type + ".querySelector no parameter"); | |
| 149 | |
| 150 test(() { // 7 | |
| 151 var result = root.querySelectorAll("*"); | |
| 152 var i = 0; | |
| 153 traverse(root, (elem) { | |
| 154 if (!identical(elem, root)) { | |
| 155 assert_equals(elem, result[i], "The result in index $i should be in tree
order."); | |
| 156 i++; | |
| 157 } | |
| 158 }); | |
| 159 }, type + ".querySelectorAll tree order"); | |
| 160 } | |
| 161 | |
| 162 /* | |
| 163 * Execute queries with the specified valid selectors for both querySelector() a
nd querySelectorAll() | |
| 164 * Only run these tests when results are expected. Don't run for syntax error te
sts. | |
| 165 */ | |
| 166 runValidSelectorTest(type, root, selectors, testType, docType) { | |
| 167 var nodeType = ""; | |
| 168 switch (root.nodeType) { | |
| 169 case Node.DOCUMENT_NODE: | |
| 170 nodeType = "document"; | |
| 171 break; | |
| 172 case Node.ELEMENT_NODE: | |
| 173 nodeType = root.parentNode != null ? "element" : "detached"; | |
| 174 break; | |
| 175 case Node.DOCUMENT_FRAGMENT_NODE: | |
| 176 nodeType = "fragment"; | |
| 177 break; | |
| 178 default: | |
| 179 throw new StateError("Reached unreachable code path."); | |
| 180 } | |
| 181 | |
| 182 for (var i = 0; i < selectors.length; i++) { | |
| 183 var s = selectors[i]; | |
| 184 var n = s["name"]; | |
| 185 var q = s["selector"]; | |
| 186 var e = s["expect"]; | |
| 187 | |
| 188 if ((s["exclude"] is! List || (s["exclude"].indexOf(nodeType) == -1 && s["ex
clude"].indexOf(docType) == -1)) | |
| 189 && (s["testType"] & testType != 0) ) { | |
| 190 //console.log("Running tests " + nodeType + ": " + s["testType"] + "&" + t
estType + "=" + (s["testType"] & testType) + ": " + JSON.stringify(s)) | |
| 191 var foundall, found; | |
| 192 | |
| 193 test(() { | |
| 194 foundall = root.querySelectorAll(q); | |
| 195 assert_not_equals(foundall, null, "The method should not return null."); | |
| 196 assert_equals(foundall.length, e.length, "The method should return the e
xpected number of matches."); | |
| 197 | |
| 198 for (var i = 0; i < e.length; i++) { | |
| 199 assert_not_equals(foundall[i], null, "The item in index $i should not
be null."); | |
| 200 assert_equals(foundall[i].attributes["id"], e[i], "The item in index $
i should have the expected ID."); | |
| 201 assert_false(foundall[i].attributes.containsKey("data-clone"), "This s
hould not be a cloned element."); | |
| 202 } | |
| 203 }, type + ".querySelectorAll: " + n + ": " + q); | |
| 204 | |
| 205 test(() { | |
| 206 found = root.querySelector(q); | |
| 207 | |
| 208 if (e.length > 0) { | |
| 209 assert_not_equals(found, null, "The method should return a match."); | |
| 210 assert_equals(found.attributes["id"], e[0], "The method should return
the first match."); | |
| 211 assert_equals(found, foundall[0], "The result should match the first i
tem from querySelectorAll."); | |
| 212 assert_false(found.attributes.containsKey("data-clone"), "This should
not be annotated as a cloned element."); | |
| 213 } else { | |
| 214 assert_equals(found, null, "The method should not match anything."); | |
| 215 } | |
| 216 }, type + ".querySelector: " + n + ": " + q); | |
| 217 } else { | |
| 218 //console.log("Excluding for " + nodeType + ": " + s["testType"] + "&" + t
estType + "=" + (s["testType"] & testType) + ": " + JSON.stringify(s)) | |
| 219 } | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 /* | |
| 224 * Execute queries with the specified invalid selectors for both querySelector()
and querySelectorAll() | |
| 225 * Only run these tests when errors are expected. Don't run for valid selector t
ests. | |
| 226 */ | |
| 227 runInvalidSelectorTest(type, root, selectors) { | |
| 228 for (var i = 0; i < selectors.length; i++) { | |
| 229 var s = selectors[i]; | |
| 230 var n = s["name"]; | |
| 231 var q = s["selector"]; | |
| 232 | |
| 233 // Dart note: FormatException seems a reasonable mapping of SyntaxError | |
| 234 test(() { | |
| 235 assert_throws((e) => e is FormatException, () { | |
| 236 root.querySelector(q); | |
| 237 }); | |
| 238 }, type + ".querySelector: " + n + ": " + q); | |
| 239 | |
| 240 test(() { | |
| 241 assert_throws((e) => e is FormatException, () { | |
| 242 root.querySelectorAll(q); | |
| 243 }); | |
| 244 }, type + ".querySelectorAll: " + n + ": " + q); | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 traverse(Node elem, fn) { | |
| 249 if (elem.nodeType == Node.ELEMENT_NODE) { | |
| 250 fn(elem); | |
| 251 } | |
| 252 | |
| 253 // Dart note: changed this since html5lib doens't support nextNode yet. | |
| 254 for (var node in elem.nodes) { | |
| 255 traverse(node, fn); | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 | |
| 260 test(Function body, String name) => unittest.test(name, body); | |
| 261 | |
| 262 assert_true(value, String reason) => | |
| 263 unittest.expect(value, true, reason: reason); | |
| 264 | |
| 265 assert_false(value, String reason) => | |
| 266 unittest.expect(value, false, reason: reason); | |
| 267 | |
| 268 assert_equals(x, y, reason) => | |
| 269 unittest.expect(x, y, reason: reason); | |
| 270 | |
| 271 assert_not_equals(x, y, reason) => | |
| 272 unittest.expect(x, unittest.isNot(y), reason: reason); | |
| 273 | |
| 274 assert_throws(exception, body, [reason]) => | |
| 275 unittest.expect(body, unittest.throwsA(exception), reason: reason); | |
| OLD | NEW |