| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library polymer.test.validator_test; |
| 6 |
| 7 import 'package:source_maps/span.dart'; |
| 8 import 'package:polymer/src/validator.dart'; |
| 9 import 'package:unittest/compact_vm_config.dart'; |
| 10 import 'package:unittest/unittest.dart'; |
| 11 |
| 12 import 'transform/common.dart'; |
| 13 |
| 14 void main() { |
| 15 useCompactVMConfiguration(); |
| 16 _testValidator('nothing to report', { |
| 17 'a|web/test.html': '<!DOCTYPE html><html></html>', |
| 18 }, { |
| 19 'a|web/test.html.messages': '', |
| 20 }); |
| 21 |
| 22 group('doctype warning', () { |
| 23 _testValidator('in web', { |
| 24 'a|web/test.html': '<html></html>', |
| 25 }, { |
| 26 'a|web/test.html.messages': |
| 27 'warning: Unexpected start tag (html). Expected DOCTYPE. ' |
| 28 '(web/test.html 0 0)', |
| 29 }); |
| 30 |
| 31 _testValidator('in lib', { |
| 32 'a|lib/test.html': '<html></html>', |
| 33 }, { |
| 34 'a|lib/test.html.messages': '', |
| 35 }); |
| 36 }); |
| 37 |
| 38 group('duplicate polymer-elements,', () { |
| 39 _testValidator('same file', { |
| 40 'a|lib/test.html': '''<html> |
| 41 <polymer-element name="a"></polymer-element> |
| 42 <polymer-element name="a"></polymer-element> |
| 43 </html>'''.replaceAll(' ', ''), |
| 44 }, { |
| 45 'a|lib/test.html.messages': |
| 46 'warning: duplicate definition for custom tag "a". ' |
| 47 '(lib/test.html 1 0)\n' |
| 48 'warning: duplicate definition for custom tag "a" ' |
| 49 '(second definition). (lib/test.html 2 0)' |
| 50 }); |
| 51 |
| 52 _testValidator('other file', { |
| 53 'a|lib/b.html': '''<html> |
| 54 <polymer-element name="a"></polymer-element> |
| 55 </html>'''.replaceAll(' ', ''), |
| 56 'a|lib/test.html': '''<html> |
| 57 <link rel="import" href="b.html"> |
| 58 <polymer-element name="a"></polymer-element> |
| 59 </html>'''.replaceAll(' ', ''), |
| 60 }, { |
| 61 'a|lib/test.html.messages': |
| 62 'warning: duplicate definition for custom tag "a". ' |
| 63 '(lib/b.html 1 0)\n' |
| 64 'warning: duplicate definition for custom tag "a" ' |
| 65 '(second definition). (lib/test.html 2 0)' |
| 66 }); |
| 67 |
| 68 _testValidator('other package', { |
| 69 'b|lib/b.html': '''<html> |
| 70 <polymer-element name="a"></polymer-element> |
| 71 </html>'''.replaceAll(' ', ''), |
| 72 'a|lib/test.html': '''<html> |
| 73 <link rel="import" href="packages/b/b.html"> |
| 74 <polymer-element name="a"></polymer-element> |
| 75 </html>'''.replaceAll(' ', ''), |
| 76 }, { |
| 77 'a|lib/test.html.messages': |
| 78 'warning: duplicate definition for custom tag "a". ' |
| 79 '(package:b/b.html 1 0)\n' |
| 80 'warning: duplicate definition for custom tag "a" ' |
| 81 '(second definition). (lib/test.html 2 0)' |
| 82 }); |
| 83 }); |
| 84 |
| 85 _testValidator('bad link-rel tag (href missing)', { |
| 86 'a|lib/test.html': '''<html> |
| 87 <link rel="import"> |
| 88 <link rel="stylesheet"> |
| 89 <link rel="foo"> |
| 90 <link rel="import" href=""> |
| 91 </html>'''.replaceAll(' ', ''), |
| 92 }, { |
| 93 'a|lib/test.html.messages': |
| 94 'warning: link rel="import" missing href. (lib/test.html 1 0)\n' |
| 95 'warning: link rel="stylesheet" missing href. (lib/test.html 2 0)\n' |
| 96 'warning: link rel="import" missing href. (lib/test.html 4 0)' |
| 97 }); |
| 98 |
| 99 _testValidator('<element> is not supported', { |
| 100 'a|lib/test.html': '''<html> |
| 101 <element name="a"></element> |
| 102 </html>'''.replaceAll(' ', ''), |
| 103 }, { |
| 104 'a|lib/test.html.messages': |
| 105 'warning: <element> elements are not supported, use <polymer-element>' |
| 106 ' instead (lib/test.html 1 0)' |
| 107 }); |
| 108 |
| 109 _testValidator('do not nest <polymer-element>', { |
| 110 'a|lib/test.html': '''<html> |
| 111 <polymer-element name="a"> |
| 112 <template><div> |
| 113 <polymer-element name="b"></polymer-element> |
| 114 </div></template> |
| 115 </polymer-element> |
| 116 </html>'''.replaceAll(' ', ''), |
| 117 }, { |
| 118 'a|lib/test.html.messages': |
| 119 'error: Nested polymer element definitions are not allowed.' |
| 120 ' (lib/test.html 3 4)' |
| 121 }); |
| 122 |
| 123 _testValidator('need a name for <polymer-element>', { |
| 124 'a|lib/test.html': '''<html> |
| 125 <polymer-element></polymer-element> |
| 126 </html>'''.replaceAll(' ', ''), |
| 127 }, { |
| 128 'a|lib/test.html.messages': |
| 129 'error: Missing tag name of the custom element. Please include an ' |
| 130 'attribute like \'name="your-tag-name"\'. (lib/test.html 1 0)' |
| 131 }); |
| 132 |
| 133 _testValidator('extend is a valid element or existing tag', { |
| 134 'a|lib/test.html': '''<html> |
| 135 <polymer-element name="x-a" extends="li"></polymer-element> |
| 136 </html>'''.replaceAll(' ', ''), |
| 137 }, { |
| 138 'a|lib/test.html.messages': '' |
| 139 }); |
| 140 |
| 141 _testValidator('extend is a valid element or existing tag', { |
| 142 'a|lib/test.html': '''<html> |
| 143 <polymer-element name="x-a" extends="x-b"></polymer-element> |
| 144 </html>'''.replaceAll(' ', ''), |
| 145 }, { |
| 146 'a|lib/test.html.messages': '' |
| 147 'warning: custom element with name "x-b" not found. ' |
| 148 '(lib/test.html 1 0)' |
| 149 }); |
| 150 |
| 151 |
| 152 group('script type matches code', () { |
| 153 _testValidator('top-level, .dart url', { |
| 154 'a|lib/test.html': '''<html> |
| 155 <script src="foo.dart"></script> |
| 156 </html>'''.replaceAll(' ', ''), |
| 157 }, { |
| 158 'a|lib/test.html.messages': |
| 159 'warning: script tag with .dart source file but no type will be ' |
| 160 'treated as JavaScript. Did you forget type="application/dart"?' |
| 161 ' (lib/test.html 1 0)' |
| 162 }); |
| 163 |
| 164 _testValidator('in polymer-element, .dart url', { |
| 165 'a|lib/test.html': '''<html> |
| 166 <polymer-element name="a"> |
| 167 <script src="foo.dart"></script> |
| 168 </polymer-element> |
| 169 </html>'''.replaceAll(' ', ''), |
| 170 }, { |
| 171 'a|lib/test.html.messages': |
| 172 'warning: script tag with .dart source file but no type will be ' |
| 173 'treated as JavaScript. Did you forget type="application/dart"?' |
| 174 ' (lib/test.html 2 0)' |
| 175 }); |
| 176 |
| 177 _testValidator('in polymer-element, .js url', { |
| 178 'a|lib/test.html': '''<html> |
| 179 <polymer-element name="a"> |
| 180 <script src="foo.js"></script> |
| 181 </polymer-element> |
| 182 </html>'''.replaceAll(' ', ''), |
| 183 }, { |
| 184 'a|lib/test.html.messages': '' |
| 185 }); |
| 186 |
| 187 _testValidator('in polymer-element, inlined', { |
| 188 'a|lib/test.html': '''<html> |
| 189 <polymer-element name="a"> |
| 190 <script>foo...</script> |
| 191 </polymer-element> |
| 192 </html>'''.replaceAll(' ', ''), |
| 193 }, { |
| 194 'a|lib/test.html.messages': |
| 195 'warning: script tag in polymer element with no type will ' |
| 196 'be treated as JavaScript. Did you forget type="application/dart"?' |
| 197 ' (lib/test.html 2 0)' |
| 198 }); |
| 199 |
| 200 _testValidator('top-level, dart type & .dart url', { |
| 201 'a|lib/test.html': '''<html> |
| 202 <script type="applicatino/dart" src="foo.dart"></script> |
| 203 </html>'''.replaceAll(' ', ''), |
| 204 }, { |
| 205 'a|lib/test.html.messages': '' |
| 206 }); |
| 207 |
| 208 _testValidator('top-level, dart type & .js url', { |
| 209 'a|lib/test.html': '''<html> |
| 210 <script type="application/dart" src="foo.js"></script> |
| 211 </html>'''.replaceAll(' ', ''), |
| 212 }, { |
| 213 'a|lib/test.html.messages': |
| 214 'warning: "application/dart" scripts should use the .dart file ' |
| 215 'extension. (lib/test.html 1 0)' |
| 216 }); |
| 217 }); |
| 218 |
| 219 _testValidator('script tags should have only src url or inline code', { |
| 220 'a|lib/test.html': '''<html> |
| 221 <script type="application/dart" src="foo.dart">more</script> |
| 222 </html>'''.replaceAll(' ', ''), |
| 223 }, { |
| 224 'a|lib/test.html.messages': |
| 225 'warning: script tag has "src" attribute and also has script text. ' |
| 226 '(lib/test.html 1 0)' |
| 227 }); |
| 228 |
| 229 group('event handlers', () { |
| 230 _testValidator('onfoo is not polymer', { |
| 231 'a|lib/test.html': '''<html><body> |
| 232 <div onfoo="something"></div> |
| 233 '''.replaceAll(' ', ''), |
| 234 }, { |
| 235 'a|lib/test.html.messages': |
| 236 'warning: Event handler "onfoo" will be interpreted as an inline ' |
| 237 'JavaScript event handler. Use the form ' |
| 238 'on-event-name="handlerName" if you want a Dart handler ' |
| 239 'that will automatically update the UI based on model changes. ' |
| 240 '(lib/test.html 1 0)' |
| 241 }); |
| 242 |
| 243 _testValidator('on-foo is only supported in polymer elements', { |
| 244 'a|lib/test.html': '''<html><body> |
| 245 <div on-foo="something"></div> |
| 246 '''.replaceAll(' ', ''), |
| 247 }, { |
| 248 'a|lib/test.html.messages': |
| 249 'warning: Inline event handlers are only supported inside ' |
| 250 'declarations of <polymer-element>. ' |
| 251 '(lib/test.html 1 0)' |
| 252 }); |
| 253 |
| 254 _testValidator('on-foo is not an expression', { |
| 255 'a|lib/test.html': '''<html><body> |
| 256 <polymer-element name="a"><div on-foo="bar()"></div> |
| 257 </polymer-element> |
| 258 '''.replaceAll(' ', ''), |
| 259 }, { |
| 260 'a|lib/test.html.messages': |
| 261 'warning: Invalid event handler body "bar()". Declare a method ' |
| 262 'in your custom element "void handlerName(event, detail, target)" ' |
| 263 'and use the form on-foo="handlerName". ' |
| 264 '(lib/test.html 1 26)' |
| 265 }); |
| 266 }); |
| 267 |
| 268 group('using custom tags', () { |
| 269 _testValidator('tag exists (x-tag)', { |
| 270 'a|lib/test.html': '<x-foo></x-foo>', |
| 271 }, { |
| 272 'a|lib/test.html.messages': |
| 273 'warning: definition for custom element with tag name "x-foo" not ' |
| 274 'found. (lib/test.html 0 0)' |
| 275 }); |
| 276 |
| 277 _testValidator('tag exists (type extension)', { |
| 278 'a|lib/test.html': '<div is="x-foo"></div>', |
| 279 }, { |
| 280 'a|lib/test.html.messages': |
| 281 'warning: definition for custom element with tag name "x-foo" not ' |
| 282 'found. (lib/test.html 0 0)' |
| 283 }); |
| 284 |
| 285 _testValidator('used correctly (no base tag)', { |
| 286 'a|lib/test.html': ''' |
| 287 <polymer-element name="x-a"></polymer-element> |
| 288 <x-a></x-a> |
| 289 '''.replaceAll(' ', ''), |
| 290 }, { |
| 291 'a|lib/test.html.messages': '' |
| 292 }); |
| 293 |
| 294 _testValidator('used incorrectly (no base tag)', { |
| 295 'a|lib/test.html': ''' |
| 296 <polymer-element name="x-a"></polymer-element> |
| 297 <div is="x-a"></div> |
| 298 '''.replaceAll(' ', ''), |
| 299 }, { |
| 300 'a|lib/test.html.messages': |
| 301 'warning: custom element "x-a" doesn\'t declare any type ' |
| 302 'extensions. To fix this, either rewrite this tag as ' |
| 303 '<x-a> or add \'extends="div"\' to ' |
| 304 'the custom element declaration. (lib/test.html 1 0)' |
| 305 }); |
| 306 |
| 307 _testValidator('used incorrectly, imported def (no base tag)', { |
| 308 'a|lib/b.html': '<polymer-element name="x-a"></polymer-element>', |
| 309 'a|lib/test.html': ''' |
| 310 <link rel="import" href="b.html"> |
| 311 <div is="x-a"></div> |
| 312 '''.replaceAll(' ', ''), |
| 313 }, { |
| 314 'a|lib/test.html.messages': |
| 315 'warning: custom element "x-a" doesn\'t declare any type ' |
| 316 'extensions. To fix this, either rewrite this tag as ' |
| 317 '<x-a> or add \'extends="div"\' to ' |
| 318 'the custom element declaration. (lib/test.html 1 0)' |
| 319 }); |
| 320 |
| 321 _testValidator('used correctly (base tag)', { |
| 322 'a|lib/b.html': ''' |
| 323 <polymer-element name="x-a" extends="div"> |
| 324 </polymer-element> |
| 325 '''.replaceAll(' ', ''), |
| 326 'a|lib/test.html': ''' |
| 327 <link rel="import" href="b.html"> |
| 328 <div is="x-a"></div> |
| 329 '''.replaceAll(' ', ''), |
| 330 }, { |
| 331 'a|lib/test.html.messages': '' |
| 332 }); |
| 333 |
| 334 _testValidator('used incorrectly (missing base tag)', { |
| 335 'a|lib/b.html': ''' |
| 336 <polymer-element name="x-a" extends="div"> |
| 337 </polymer-element> |
| 338 '''.replaceAll(' ', ''), |
| 339 'a|lib/test.html': ''' |
| 340 <link rel="import" href="b.html"> |
| 341 <x-a></x-a> |
| 342 '''.replaceAll(' ', ''), |
| 343 }, { |
| 344 'a|lib/test.html.messages': '' |
| 345 'warning: custom element "x-a" extends from "div", but this tag ' |
| 346 'will not include the default properties of "div". To fix this, ' |
| 347 'either write this tag as <div is="x-a"> or remove the "extends" ' |
| 348 'attribute from the custom element declaration. (lib/test.html 1 0)' |
| 349 }); |
| 350 |
| 351 _testValidator('used incorrectly (wrong base tag)', { |
| 352 'a|lib/b.html': ''' |
| 353 <polymer-element name="x-a" extends="div"> |
| 354 </polymer-element> |
| 355 '''.replaceAll(' ', ''), |
| 356 'a|lib/test.html': ''' |
| 357 <link rel="import" href="b.html"> |
| 358 <span is="x-a"></span> |
| 359 '''.replaceAll(' ', ''), |
| 360 }, { |
| 361 'a|lib/test.html.messages': '' |
| 362 'warning: custom element "x-a" extends from "div". Did you mean ' |
| 363 'to write <div is="x-a">? (lib/test.html 1 0)' |
| 364 }); |
| 365 |
| 366 _testValidator('used incorrectly (wrong base tag, transitive)', { |
| 367 'a|lib/c.html': ''' |
| 368 <polymer-element name="x-c" extends="li"> |
| 369 </polymer-element> |
| 370 <polymer-element name="x-b" extends="x-c"> |
| 371 </polymer-element> |
| 372 '''.replaceAll(' ', ''), |
| 373 'a|lib/b.html': ''' |
| 374 <link rel="import" href="c.html"> |
| 375 <polymer-element name="x-a" extends="x-b"> |
| 376 </polymer-element> |
| 377 '''.replaceAll(' ', ''), |
| 378 'a|lib/test.html': ''' |
| 379 <link rel="import" href="b.html"> |
| 380 <span is="x-a"></span> |
| 381 '''.replaceAll(' ', ''), |
| 382 }, { |
| 383 'a|lib/test.html.messages': '' |
| 384 'warning: custom element "x-a" extends from "li". Did you mean ' |
| 385 'to write <li is="x-a">? (lib/test.html 1 0)' |
| 386 }); |
| 387 }); |
| 388 } |
| 389 |
| 390 _testValidator(String name, Map inputFiles, Map outputMessages) { |
| 391 var validator = new Validator(_testFormatter); |
| 392 var outputFiles = {}; |
| 393 inputFiles.forEach((k, v) => outputFiles[k] = v); |
| 394 outputMessages.forEach((k, v) => outputFiles[k] = v); |
| 395 var keys = inputFiles.keys.toSet(); |
| 396 keys.retainAll(outputMessages.keys); |
| 397 expect(keys, isEmpty); |
| 398 testPhases(name, [[validator]], inputFiles, outputFiles); |
| 399 } |
| 400 |
| 401 |
| 402 _testFormatter(String kind, String message, Span span) { |
| 403 var formattedMessage = '$kind: $message'; |
| 404 if (span != null) { |
| 405 formattedMessage = '$formattedMessage ' |
| 406 '(${span.sourceUrl} ${span.start.line} ${span.start.column})'; |
| 407 } |
| 408 return formattedMessage; |
| 409 } |
| OLD | NEW |