| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library polymer.test.linter_test; | 5 library polymer.test.linter_test; |
| 6 | 6 |
| 7 import 'package:polymer/src/build/common.dart'; | 7 import 'package:polymer/src/build/common.dart'; |
| 8 import 'package:polymer/src/build/linter.dart'; | 8 import 'package:polymer/src/build/linter.dart'; |
| 9 import 'package:source_maps/span.dart'; | 9 import 'package:source_maps/span.dart'; |
| 10 import 'package:unittest/compact_vm_config.dart'; | 10 import 'package:unittest/compact_vm_config.dart'; |
| 11 import 'package:unittest/unittest.dart'; | 11 import 'package:unittest/unittest.dart'; |
| 12 | 12 |
| 13 import 'common.dart'; | 13 import 'common.dart'; |
| 14 | 14 |
| 15 void main() { | 15 void main() { |
| 16 useCompactVMConfiguration(); | 16 useCompactVMConfiguration(); |
| 17 _testLinter('nothing to report', { | 17 _testLinter('nothing to report', { |
| 18 'a|lib/test.html': '<!DOCTYPE html><html></html>', | 18 'a|lib/test.html': '<!DOCTYPE html><html></html>', |
| 19 }, { | 19 }, []); |
| 20 'a|lib/test.html.messages': '' | |
| 21 }); | |
| 22 | 20 |
| 23 group('must have Dart code to invoke initPolymer, dart.js, not boot.js', () { | 21 group('must have Dart code to invoke initPolymer, dart.js, not boot.js', () { |
| 24 _testLinter('nothing to report', { | 22 _testLinter('nothing to report', { |
| 25 'a|web/test.html': '<!DOCTYPE html><html>' | 23 'a|web/test.html': '<!DOCTYPE html><html>' |
| 26 '<script type="application/dart" src="foo.dart">' | 24 '<script type="application/dart" src="foo.dart">' |
| 27 '</script>' | 25 '</script>' |
| 28 '<script src="packages/browser/dart.js"></script>' | 26 '<script src="packages/browser/dart.js"></script>' |
| 29 '</html>', | 27 '</html>', |
| 30 }, { | 28 }, []); |
| 31 'a|web/test.html.messages': '', | |
| 32 }); | |
| 33 | 29 |
| 34 _testLinter('missing Dart code and dart.js', { | 30 _testLinter('missing Dart code and dart.js', { |
| 35 'a|web/test.html': '<!DOCTYPE html><html></html>', | 31 'a|web/test.html': '<!DOCTYPE html><html></html>', |
| 36 }, { | 32 }, [ |
| 37 'a|web/test.html.messages': 'error: $USE_INIT_DART', | 33 'error: $USE_INIT_DART', |
| 38 }); | 34 ]); |
| 39 | 35 |
| 40 _testLinter('using deprecated boot.js', { | 36 _testLinter('using deprecated boot.js', { |
| 41 'a|web/test.html': '<!DOCTYPE html><html>\n' | 37 'a|web/test.html': '<!DOCTYPE html><html>\n' |
| 42 '<script src="packages/polymer/boot.js"></script>' | 38 '<script src="packages/polymer/boot.js"></script>' |
| 43 '<script type="application/dart" src="foo.dart">' | 39 '<script type="application/dart" src="foo.dart">' |
| 44 '</script>' | 40 '</script>' |
| 45 '<script src="packages/browser/dart.js"></script>' | 41 '<script src="packages/browser/dart.js"></script>' |
| 46 '</html>', | 42 '</html>', |
| 47 }, { | 43 }, [ |
| 48 'a|web/test.html.messages': 'warning: $BOOT_JS_DEPRECATED ' | 44 'warning: $BOOT_JS_DEPRECATED (web/test.html 1 0)', |
| 49 '(web/test.html 1 0)', | 45 ]); |
| 50 }); | |
| 51 }); | 46 }); |
| 52 group('single script tag per document', () { | 47 group('single script tag per document', () { |
| 53 _testLinter('two top-level tags', { | 48 _testLinter('two top-level tags', { |
| 54 'a|web/test.html': '<!DOCTYPE html><html>' | 49 'a|web/test.html': '<!DOCTYPE html><html>' |
| 55 '<script type="application/dart" src="a.dart">' | 50 '<script type="application/dart" src="a.dart">' |
| 56 '</script>\n' | 51 '</script>\n' |
| 57 '<script type="application/dart" src="b.dart">' | 52 '<script type="application/dart" src="b.dart">' |
| 58 '</script>' | 53 '</script>' |
| 59 '<script src="packages/browser/dart.js"></script>' | 54 '<script src="packages/browser/dart.js"></script>' |
| 60 }, { | 55 }, [ |
| 61 'a|web/test.html.messages': | 56 'warning: Only one "application/dart" script tag per document is' |
| 62 'warning: Only one "application/dart" script tag per document is' | 57 ' allowed. (web/test.html 1 0)', |
| 63 ' allowed. (web/test.html 1 0)', | 58 ]); |
| 64 }); | |
| 65 | 59 |
| 66 _testLinter('two top-level tags, non entrypoint', { | 60 _testLinter('two top-level tags, non entrypoint', { |
| 67 'a|lib/test.html': '<!DOCTYPE html><html>' | 61 'a|lib/test.html': '<!DOCTYPE html><html>' |
| 68 '<script type="application/dart" src="a.dart">' | 62 '<script type="application/dart" src="a.dart">' |
| 69 '</script>\n' | 63 '</script>\n' |
| 70 '<script type="application/dart" src="b.dart">' | 64 '<script type="application/dart" src="b.dart">' |
| 71 '</script>' | 65 '</script>' |
| 72 '<script src="packages/browser/dart.js"></script>' | 66 '<script src="packages/browser/dart.js"></script>' |
| 73 }, { | 67 }, [ |
| 74 'a|lib/test.html.messages': | 68 'warning: Only one "application/dart" script tag per document is' |
| 75 'warning: Only one "application/dart" script tag per document is' | 69 ' allowed. (lib/test.html 1 0)', |
| 76 ' allowed. (lib/test.html 1 0)', | 70 ]); |
| 77 }); | |
| 78 | 71 |
| 79 _testLinter('tags inside elements', { | 72 _testLinter('tags inside elements', { |
| 80 'a|web/test.html': '<!DOCTYPE html><html>' | 73 'a|web/test.html': '<!DOCTYPE html><html>' |
| 81 '<polymer-element name="x-a">' | 74 '<polymer-element name="x-a">' |
| 82 '<script type="application/dart" src="a.dart">' | 75 '<script type="application/dart" src="a.dart">' |
| 83 '</script>' | 76 '</script>' |
| 84 '</polymer-element>\n' | 77 '</polymer-element>\n' |
| 85 '<script type="application/dart" src="b.dart">' | 78 '<script type="application/dart" src="b.dart">' |
| 86 '</script>' | 79 '</script>' |
| 87 '<script src="packages/browser/dart.js"></script>' | 80 '<script src="packages/browser/dart.js"></script>' |
| 88 }, { | 81 }, [ |
| 89 'a|web/test.html.messages': | 82 'warning: Only one "application/dart" script tag per document is' |
| 90 'warning: Only one "application/dart" script tag per document is' | 83 ' allowed. (web/test.html 1 0)', |
| 91 ' allowed. (web/test.html 1 0)', | 84 ]); |
| 92 }); | |
| 93 }); | 85 }); |
| 94 | 86 |
| 95 group('doctype warning', () { | 87 group('doctype warning', () { |
| 96 _testLinter('in web', { | 88 _testLinter('in web', { |
| 97 'a|web/test.html': '<html></html>', | 89 'a|web/test.html': '<html></html>', |
| 98 }, { | 90 }, [ |
| 99 'a|web/test.html.messages': | 91 'warning: Unexpected start tag (html). Expected DOCTYPE. ' |
| 100 'warning: Unexpected start tag (html). Expected DOCTYPE. ' | 92 '(web/test.html 0 0)', |
| 101 '(web/test.html 0 0)\n' | 93 'error: $USE_INIT_DART', |
| 102 'error: $USE_INIT_DART', | 94 ]); |
| 103 }); | |
| 104 | 95 |
| 105 _testLinter('in lib', { | 96 _testLinter('in lib', { |
| 106 'a|lib/test.html': '<html></html>', | 97 'a|lib/test.html': '<html></html>', |
| 107 }, { | 98 }, []); |
| 108 'a|lib/test.html.messages': '', | |
| 109 }); | |
| 110 }); | 99 }); |
| 111 | 100 |
| 112 group('duplicate polymer-elements,', () { | 101 group('duplicate polymer-elements,', () { |
| 113 _testLinter('same file', { | 102 _testLinter('same file', { |
| 114 'a|lib/test.html': '''<html> | 103 'a|lib/test.html': '''<html> |
| 115 <polymer-element name="x-a"></polymer-element> | 104 <polymer-element name="x-a"></polymer-element> |
| 116 <polymer-element name="x-a"></polymer-element> | 105 <polymer-element name="x-a"></polymer-element> |
| 117 </html>'''.replaceAll(' ', ''), | 106 </html>'''.replaceAll(' ', ''), |
| 118 }, { | 107 }, [ |
| 119 'a|lib/test.html.messages': | 108 'warning: duplicate definition for custom tag "x-a". ' |
| 120 'warning: duplicate definition for custom tag "x-a". ' | 109 '(lib/test.html 1 0)', |
| 121 '(lib/test.html 1 0)\n' | 110 'warning: duplicate definition for custom tag "x-a" ' |
| 122 'warning: duplicate definition for custom tag "x-a" ' | 111 '(second definition). (lib/test.html 2 0)' |
| 123 '(second definition). (lib/test.html 2 0)' | 112 ]); |
| 124 }); | |
| 125 | 113 |
| 126 _testLinter('other file', { | 114 _testLinter('other file', { |
| 127 'a|lib/b.html': '''<html> | 115 'a|lib/b.html': '''<html> |
| 128 <polymer-element name="x-a"></polymer-element> | 116 <polymer-element name="x-a"></polymer-element> |
| 129 </html>'''.replaceAll(' ', ''), | 117 </html>'''.replaceAll(' ', ''), |
| 130 'a|lib/test.html': '''<html> | 118 'a|lib/test.html': '''<html> |
| 131 <link rel="import" href="b.html"> | 119 <link rel="import" href="b.html"> |
| 132 <polymer-element name="x-a"></polymer-element> | 120 <polymer-element name="x-a"></polymer-element> |
| 133 </html>'''.replaceAll(' ', ''), | 121 </html>'''.replaceAll(' ', ''), |
| 134 }, { | 122 }, [ |
| 135 'a|lib/test.html.messages': | 123 'warning: duplicate definition for custom tag "x-a". ' |
| 136 'warning: duplicate definition for custom tag "x-a". ' | 124 '(lib/b.html 1 0)', |
| 137 '(lib/b.html 1 0)\n' | 125 'warning: duplicate definition for custom tag "x-a" ' |
| 138 'warning: duplicate definition for custom tag "x-a" ' | 126 '(second definition). (lib/test.html 2 0)' |
| 139 '(second definition). (lib/test.html 2 0)' | 127 ]); |
| 140 }); | |
| 141 | 128 |
| 142 _testLinter('non existing file', { | 129 _testLinter('non existing file', { |
| 143 'a|lib/test.html': '''<html> | 130 'a|lib/test.html': '''<html> |
| 144 <link rel="import" href="b.html"> | 131 <link rel="import" href="b.html"> |
| 145 <polymer-element name="x-a"></polymer-element> | 132 <polymer-element name="x-a"></polymer-element> |
| 146 </html>'''.replaceAll(' ', ''), | 133 </html>'''.replaceAll(' ', ''), |
| 147 }, { | 134 }, [ |
| 148 'a|lib/test.html.messages': | 135 'error: couldn\'t find imported asset "lib/b.html" in package ' |
| 149 'error: couldn\'t find imported asset "lib/b.html" in package ' | 136 '"a". (lib/test.html 1 0)' |
| 150 '"a". (lib/test.html 1 0)' | 137 ]); |
| 151 }); | |
| 152 | 138 |
| 153 _testLinter('other package', { | 139 _testLinter('other package', { |
| 154 'b|lib/b.html': '''<html> | 140 'b|lib/b.html': '''<html> |
| 155 <polymer-element name="x-a"></polymer-element> | 141 <polymer-element name="x-a"></polymer-element> |
| 156 </html>'''.replaceAll(' ', ''), | 142 </html>'''.replaceAll(' ', ''), |
| 157 'a|lib/test.html': '''<html> | 143 'a|lib/test.html': '''<html> |
| 158 <link rel="import" href="../../packages/b/b.html"> | 144 <link rel="import" href="../../packages/b/b.html"> |
| 159 <polymer-element name="x-a"></polymer-element> | 145 <polymer-element name="x-a"></polymer-element> |
| 160 </html>'''.replaceAll(' ', ''), | 146 </html>'''.replaceAll(' ', ''), |
| 161 }, { | 147 }, [ |
| 162 'a|lib/test.html.messages': | 148 'warning: duplicate definition for custom tag "x-a". ' |
| 163 'warning: duplicate definition for custom tag "x-a". ' | 149 '(package:b/b.html 1 0)', |
| 164 '(package:b/b.html 1 0)\n' | 150 'warning: duplicate definition for custom tag "x-a" ' |
| 165 'warning: duplicate definition for custom tag "x-a" ' | 151 '(second definition). (lib/test.html 2 0)' |
| 166 '(second definition). (lib/test.html 2 0)' | 152 ]); |
| 167 }); | |
| 168 }); | 153 }); |
| 169 | 154 |
| 170 _testLinter('bad link-rel tag (href missing)', { | 155 _testLinter('bad link-rel tag (href missing)', { |
| 171 'a|lib/test.html': '''<html> | 156 'a|lib/test.html': '''<html> |
| 172 <link rel="import"> | 157 <link rel="import"> |
| 173 <link rel="stylesheet"> | 158 <link rel="stylesheet"> |
| 174 <link rel="foo"> | 159 <link rel="foo"> |
| 175 <link rel="import" href=""> | 160 <link rel="import" href=""> |
| 176 </html>'''.replaceAll(' ', ''), | 161 </html>'''.replaceAll(' ', ''), |
| 177 }, { | 162 }, [ |
| 178 'a|lib/test.html.messages': | 163 'warning: link rel="import" missing href. (lib/test.html 1 0)', |
| 179 'warning: link rel="import" missing href. (lib/test.html 1 0)\n' | 164 'warning: link rel="stylesheet" missing href. (lib/test.html 2 0)', |
| 180 'warning: link rel="stylesheet" missing href. (lib/test.html 2 0)\n' | 165 'warning: link rel="import" missing href. (lib/test.html 4 0)' |
| 181 'warning: link rel="import" missing href. (lib/test.html 4 0)' | 166 ]); |
| 182 }); | |
| 183 | 167 |
| 184 _testLinter('<element> is not supported', { | 168 _testLinter('<element> is not supported', { |
| 185 'a|lib/test.html': '''<html> | 169 'a|lib/test.html': '''<html> |
| 186 <element name="x-a"></element> | 170 <element name="x-a"></element> |
| 187 </html>'''.replaceAll(' ', ''), | 171 </html>'''.replaceAll(' ', ''), |
| 188 }, { | 172 }, [ |
| 189 'a|lib/test.html.messages': | 173 'warning: <element> elements are not supported, use <polymer-element>' |
| 190 'warning: <element> elements are not supported, use <polymer-element>' | 174 ' instead (lib/test.html 1 0)' |
| 191 ' instead (lib/test.html 1 0)' | 175 ]); |
| 192 }); | |
| 193 | 176 |
| 194 _testLinter('do not nest <polymer-element>', { | 177 _testLinter('do not nest <polymer-element>', { |
| 195 'a|lib/test.html': '''<html> | 178 'a|lib/test.html': '''<html> |
| 196 <polymer-element name="x-a"> | 179 <polymer-element name="x-a"> |
| 197 <template><div> | 180 <template><div> |
| 198 <polymer-element name="b"></polymer-element> | 181 <polymer-element name="b"></polymer-element> |
| 199 </div></template> | 182 </div></template> |
| 200 </polymer-element> | 183 </polymer-element> |
| 201 </html>'''.replaceAll(' ', ''), | 184 </html>'''.replaceAll(' ', ''), |
| 202 }, { | 185 }, [ |
| 203 'a|lib/test.html.messages': | 186 'error: Nested polymer element definitions are not allowed.' |
| 204 'error: Nested polymer element definitions are not allowed.' | 187 ' (lib/test.html 3 4)' |
| 205 ' (lib/test.html 3 4)' | 188 ]); |
| 206 }); | |
| 207 | 189 |
| 208 _testLinter('need a name for <polymer-element>', { | 190 _testLinter('need a name for <polymer-element>', { |
| 209 'a|lib/test.html': '''<html> | 191 'a|lib/test.html': '''<html> |
| 210 <polymer-element></polymer-element> | 192 <polymer-element></polymer-element> |
| 211 </html>'''.replaceAll(' ', ''), | 193 </html>'''.replaceAll(' ', ''), |
| 212 }, { | 194 }, [ |
| 213 'a|lib/test.html.messages': | 195 'error: Missing tag name of the custom element. Please include an ' |
| 214 'error: Missing tag name of the custom element. Please include an ' | 196 'attribute like \'name="your-tag-name"\'. (lib/test.html 1 0)' |
| 215 'attribute like \'name="your-tag-name"\'. (lib/test.html 1 0)' | 197 ]); |
| 216 }); | |
| 217 | 198 |
| 218 _testLinter('name for <polymer-element> should have dashes', { | 199 _testLinter('name for <polymer-element> should have dashes', { |
| 219 'a|lib/test.html': '''<html> | 200 'a|lib/test.html': '''<html> |
| 220 <polymer-element name="a"></polymer-element> | 201 <polymer-element name="a"></polymer-element> |
| 221 </html>'''.replaceAll(' ', ''), | 202 </html>'''.replaceAll(' ', ''), |
| 222 }, { | 203 }, [ |
| 223 'a|lib/test.html.messages': | 204 'error: Invalid name "a". Custom element names must have at least one' |
| 224 'error: Invalid name "a". Custom element names must have at least one' | 205 ' dash and can\'t be any of the following names: annotation-xml, ' |
| 225 ' dash and can\'t be any of the following names: annotation-xml, ' | 206 'color-profile, font-face, font-face-src, font-face-uri, ' |
| 226 'color-profile, font-face, font-face-src, font-face-uri, ' | 207 'font-face-format, font-face-name, missing-glyph. (lib/test.html 1 0)' |
| 227 'font-face-format, font-face-name, missing-glyph. (lib/test.html 1 0)' | 208 ]); |
| 228 }); | |
| 229 | 209 |
| 230 _testLinter('extend is a valid element or existing tag', { | 210 _testLinter('extend is a valid element or existing tag', { |
| 231 'a|lib/test.html': '''<html> | 211 'a|lib/test.html': '''<html> |
| 232 <polymer-element name="x-a" extends="li"></polymer-element> | 212 <polymer-element name="x-a" extends="li"></polymer-element> |
| 233 </html>'''.replaceAll(' ', ''), | 213 </html>'''.replaceAll(' ', ''), |
| 234 }, { | 214 }, []); |
| 235 'a|lib/test.html.messages': '' | |
| 236 }); | |
| 237 | 215 |
| 238 _testLinter('extend is a valid element or existing tag', { | 216 _testLinter('extend is a valid element or existing tag', { |
| 239 'a|lib/test.html': '''<html> | 217 'a|lib/test.html': '''<html> |
| 240 <polymer-element name="x-a" extends="x-b"></polymer-element> | 218 <polymer-element name="x-a" extends="x-b"></polymer-element> |
| 241 </html>'''.replaceAll(' ', ''), | 219 </html>'''.replaceAll(' ', ''), |
| 242 }, { | 220 }, [ |
| 243 'a|lib/test.html.messages': '' | 221 'warning: custom element with name "x-b" not found. (lib/test.html 1 0)' |
| 244 'warning: custom element with name "x-b" not found. ' | 222 ]); |
| 245 '(lib/test.html 1 0)' | |
| 246 }); | |
| 247 | 223 |
| 248 | 224 |
| 249 group('script type matches code', () { | 225 group('script type matches code', () { |
| 250 _testLinter('top-level, .dart url', { | 226 _testLinter('top-level, .dart url', { |
| 251 'a|lib/test.html': '''<html> | 227 'a|lib/test.html': '''<html> |
| 252 <script src="foo.dart"></script> | 228 <script src="foo.dart"></script> |
| 253 </html>'''.replaceAll(' ', ''), | 229 </html>'''.replaceAll(' ', ''), |
| 254 }, { | 230 }, [ |
| 255 'a|lib/test.html.messages': | 231 'warning: Wrong script type, expected type="application/dart".' |
| 256 'warning: Wrong script type, expected type="application/dart".' | 232 ' (lib/test.html 1 0)' |
| 257 ' (lib/test.html 1 0)' | 233 ]); |
| 258 }); | |
| 259 | 234 |
| 260 _testLinter('in polymer-element, .dart url', { | 235 _testLinter('in polymer-element, .dart url', { |
| 261 'a|lib/test.html': '''<html> | 236 'a|lib/test.html': '''<html> |
| 262 <polymer-element name="x-a"> | 237 <polymer-element name="x-a"> |
| 263 <script src="foo.dart"></script> | 238 <script src="foo.dart"></script> |
| 264 </polymer-element> | 239 </polymer-element> |
| 265 </html>'''.replaceAll(' ', ''), | 240 </html>'''.replaceAll(' ', ''), |
| 266 }, { | 241 }, [ |
| 267 'a|lib/test.html.messages': | 242 'warning: Wrong script type, expected type="application/dart".' |
| 268 'warning: Wrong script type, expected type="application/dart".' | 243 ' (lib/test.html 2 0)' |
| 269 ' (lib/test.html 2 0)' | 244 ]); |
| 270 }); | |
| 271 | 245 |
| 272 _testLinter('in polymer-element, .js url', { | 246 _testLinter('in polymer-element, .js url', { |
| 273 'a|lib/test.html': '''<html> | 247 'a|lib/test.html': '''<html> |
| 274 <polymer-element name="x-a"> | 248 <polymer-element name="x-a"> |
| 275 <script src="foo.js"></script> | 249 <script src="foo.js"></script> |
| 276 </polymer-element> | 250 </polymer-element> |
| 277 </html>'''.replaceAll(' ', ''), | 251 </html>'''.replaceAll(' ', ''), |
| 278 }, { | 252 }, []); |
| 279 'a|lib/test.html.messages': '' | |
| 280 }); | |
| 281 | 253 |
| 282 _testLinter('in polymer-element, inlined', { | 254 _testLinter('in polymer-element, inlined', { |
| 283 'a|lib/test.html': '''<html> | 255 'a|lib/test.html': '''<html> |
| 284 <polymer-element name="x-a"> | 256 <polymer-element name="x-a"> |
| 285 <script>foo...</script> | 257 <script>foo...</script> |
| 286 </polymer-element> | 258 </polymer-element> |
| 287 </html>'''.replaceAll(' ', ''), | 259 </html>'''.replaceAll(' ', ''), |
| 288 }, { | 260 }, [ |
| 289 'a|lib/test.html.messages': | 261 'warning: script tag in polymer element with no type will ' |
| 290 'warning: script tag in polymer element with no type will ' | 262 'be treated as JavaScript. Did you forget type="application/dart"?' |
| 291 'be treated as JavaScript. Did you forget type="application/dart"?' | 263 ' (lib/test.html 2 0)' |
| 292 ' (lib/test.html 2 0)' | 264 ]); |
| 293 }); | |
| 294 | 265 |
| 295 _testLinter('top-level, dart type & .dart url', { | 266 _testLinter('top-level, dart type & .dart url', { |
| 296 'a|lib/test.html': '''<html> | 267 'a|lib/test.html': '''<html> |
| 297 <script type="application/dart" src="foo.dart"></script> | 268 <script type="application/dart" src="foo.dart"></script> |
| 298 </html>'''.replaceAll(' ', ''), | 269 </html>'''.replaceAll(' ', ''), |
| 299 }, { | 270 }, []); |
| 300 'a|lib/test.html.messages': '' | |
| 301 }); | |
| 302 | 271 |
| 303 _testLinter('top-level, dart type & .js url', { | 272 _testLinter('top-level, dart type & .js url', { |
| 304 'a|lib/test.html': '''<html> | 273 'a|lib/test.html': '''<html> |
| 305 <script type="application/dart" src="foo.js"></script> | 274 <script type="application/dart" src="foo.js"></script> |
| 306 </html>'''.replaceAll(' ', ''), | 275 </html>'''.replaceAll(' ', ''), |
| 307 }, { | 276 }, [ |
| 308 'a|lib/test.html.messages': | 277 'warning: "application/dart" scripts should use the .dart file ' |
| 309 'warning: "application/dart" scripts should use the .dart file ' | 278 'extension. (lib/test.html 1 0)' |
| 310 'extension. (lib/test.html 1 0)' | 279 ]); |
| 311 }); | |
| 312 }); | 280 }); |
| 313 | 281 |
| 314 _testLinter('script tags should have only src url or inline code', { | 282 _testLinter('script tags should have only src url or inline code', { |
| 315 'a|lib/test.html': '''<html> | 283 'a|lib/test.html': '''<html> |
| 316 <script type="application/dart" src="foo.dart">more</script> | 284 <script type="application/dart" src="foo.dart">more</script> |
| 317 </html>'''.replaceAll(' ', ''), | 285 </html>'''.replaceAll(' ', ''), |
| 318 }, { | 286 }, [ |
| 319 'a|lib/test.html.messages': | 287 'warning: script tag has "src" attribute and also has script text. ' |
| 320 'warning: script tag has "src" attribute and also has script text. ' | 288 '(lib/test.html 1 0)' |
| 321 '(lib/test.html 1 0)' | 289 ]); |
| 322 }); | |
| 323 | 290 |
| 324 group('event handlers', () { | 291 group('event handlers', () { |
| 325 _testLinter('onfoo is not polymer', { | 292 _testLinter('onfoo is not polymer', { |
| 326 'a|lib/test.html': '''<html><body> | 293 'a|lib/test.html': '''<html><body> |
| 327 <div onfoo="something"></div> | 294 <div onfoo="something"></div> |
| 328 '''.replaceAll(' ', ''), | 295 '''.replaceAll(' ', ''), |
| 329 }, { | 296 }, [ |
| 330 'a|lib/test.html.messages': | 297 'warning: Event handler "onfoo" will be interpreted as an inline ' |
| 331 'warning: Event handler "onfoo" will be interpreted as an inline ' | 298 'JavaScript event handler. Use the form ' |
| 332 'JavaScript event handler. Use the form ' | 299 'on-event-name="handlerName" if you want a Dart handler ' |
| 333 'on-event-name="handlerName" if you want a Dart handler ' | 300 'that will automatically update the UI based on model changes. ' |
| 334 'that will automatically update the UI based on model changes. ' | 301 '(lib/test.html 1 5)' |
| 335 '(lib/test.html 1 5)' | 302 ]); |
| 336 }); | |
| 337 | 303 |
| 338 _testLinter('on-foo is only supported in polymer elements', { | 304 _testLinter('on-foo is only supported in polymer elements', { |
| 339 'a|lib/test.html': '''<html><body> | 305 'a|lib/test.html': '''<html><body> |
| 340 <div on-foo="something"></div> | 306 <div on-foo="something"></div> |
| 341 '''.replaceAll(' ', ''), | 307 '''.replaceAll(' ', ''), |
| 342 }, { | 308 }, [ |
| 343 'a|lib/test.html.messages': | 309 'warning: Inline event handlers are only supported inside ' |
| 344 'warning: Inline event handlers are only supported inside ' | 310 'declarations of <polymer-element>. ' |
| 345 'declarations of <polymer-element>. ' | 311 '(lib/test.html 1 5)' |
| 346 '(lib/test.html 1 5)' | 312 ]); |
| 347 }); | |
| 348 | 313 |
| 349 _testLinter('on-foo is not an expression', { | 314 _testLinter('on-foo is not an expression', { |
| 350 'a|lib/test.html': '''<html><body> | 315 'a|lib/test.html': '''<html><body> |
| 351 <polymer-element name="x-a"><div on-foo="bar()"></div> | 316 <polymer-element name="x-a"><div on-foo="bar()"></div> |
| 352 </polymer-element> | 317 </polymer-element> |
| 353 '''.replaceAll(' ', ''), | 318 '''.replaceAll(' ', ''), |
| 354 }, { | 319 }, [ |
| 355 'a|lib/test.html.messages': | 320 'warning: Invalid event handler body "bar()". Declare a method ' |
| 356 'warning: Invalid event handler body "bar()". Declare a method ' | 321 'in your custom element "void handlerName(event, detail, target)" ' |
| 357 'in your custom element "void handlerName(event, detail, target)" ' | 322 'and use the form on-foo="handlerName". ' |
| 358 'and use the form on-foo="handlerName". ' | 323 '(lib/test.html 1 33)' |
| 359 '(lib/test.html 1 33)' | 324 ]); |
| 360 }); | |
| 361 | 325 |
| 362 _testLinter('on-foo-bar is supported as a custom event name', { | 326 _testLinter('on-foo-bar is supported as a custom event name', { |
| 363 'a|lib/test.html': '''<html><body> | 327 'a|lib/test.html': '''<html><body> |
| 364 <polymer-element name="x-a"><div on-foo-bar="quux"></div> | 328 <polymer-element name="x-a"><div on-foo-bar="quux"></div> |
| 365 </polymer-element> | 329 </polymer-element> |
| 366 '''.replaceAll(' ', ''), | 330 '''.replaceAll(' ', ''), |
| 367 }, {}); | 331 }, []); |
| 368 }); | 332 }); |
| 369 | 333 |
| 370 group('using custom tags', () { | 334 group('using custom tags', () { |
| 371 _testLinter('tag exists (x-tag)', { | 335 _testLinter('tag exists (x-tag)', { |
| 372 'a|lib/test.html': '<x-foo></x-foo>', | 336 'a|lib/test.html': '<x-foo></x-foo>', |
| 373 }, { | 337 }, [ |
| 374 'a|lib/test.html.messages': | 338 'warning: definition for Polymer element with tag name "x-foo" not ' |
| 375 'warning: definition for Polymer element with tag name "x-foo" not ' | 339 'found. (lib/test.html 0 0)' |
| 376 'found. (lib/test.html 0 0)' | 340 ]); |
| 377 }); | |
| 378 | 341 |
| 379 _testLinter('tag exists (type extension)', { | 342 _testLinter('tag exists (type extension)', { |
| 380 'a|lib/test.html': '<div is="x-foo"></div>', | 343 'a|lib/test.html': '<div is="x-foo"></div>', |
| 381 }, { | 344 }, [ |
| 382 'a|lib/test.html.messages': | 345 'warning: definition for Polymer element with tag name "x-foo" not ' |
| 383 'warning: definition for Polymer element with tag name "x-foo" not ' | 346 'found. (lib/test.html 0 0)' |
| 384 'found. (lib/test.html 0 0)' | 347 ]); |
| 385 }); | |
| 386 | 348 |
| 387 _testLinter('used correctly (no base tag)', { | 349 _testLinter('used correctly (no base tag)', { |
| 388 'a|lib/test.html': ''' | 350 'a|lib/test.html': ''' |
| 389 <polymer-element name="x-a"></polymer-element> | 351 <polymer-element name="x-a"></polymer-element> |
| 390 <x-a></x-a> | 352 <x-a></x-a> |
| 391 '''.replaceAll(' ', ''), | 353 '''.replaceAll(' ', ''), |
| 392 }, { | 354 }, []); |
| 393 'a|lib/test.html.messages': '' | |
| 394 }); | |
| 395 | 355 |
| 396 _testLinter('used incorrectly (no base tag)', { | 356 _testLinter('used incorrectly (no base tag)', { |
| 397 'a|lib/test.html': ''' | 357 'a|lib/test.html': ''' |
| 398 <polymer-element name="x-a"></polymer-element> | 358 <polymer-element name="x-a"></polymer-element> |
| 399 <div is="x-a"></div> | 359 <div is="x-a"></div> |
| 400 '''.replaceAll(' ', ''), | 360 '''.replaceAll(' ', ''), |
| 401 }, { | 361 }, [ |
| 402 'a|lib/test.html.messages': | 362 'warning: custom element "x-a" doesn\'t declare any type ' |
| 403 'warning: custom element "x-a" doesn\'t declare any type ' | 363 'extensions. To fix this, either rewrite this tag as ' |
| 404 'extensions. To fix this, either rewrite this tag as ' | 364 '<x-a> or add \'extends="div"\' to ' |
| 405 '<x-a> or add \'extends="div"\' to ' | 365 'the custom element declaration. (lib/test.html 1 0)' |
| 406 'the custom element declaration. (lib/test.html 1 0)' | 366 ]); |
| 407 }); | |
| 408 | 367 |
| 409 _testLinter('used incorrectly, imported def (no base tag)', { | 368 _testLinter('used incorrectly, imported def (no base tag)', { |
| 410 'a|lib/b.html': '<polymer-element name="x-a"></polymer-element>', | 369 'a|lib/b.html': '<polymer-element name="x-a"></polymer-element>', |
| 411 'a|lib/test.html': ''' | 370 'a|lib/test.html': ''' |
| 412 <link rel="import" href="b.html"> | 371 <link rel="import" href="b.html"> |
| 413 <div is="x-a"></div> | 372 <div is="x-a"></div> |
| 414 '''.replaceAll(' ', ''), | 373 '''.replaceAll(' ', ''), |
| 415 }, { | 374 }, [ |
| 416 'a|lib/test.html.messages': | 375 'warning: custom element "x-a" doesn\'t declare any type ' |
| 417 'warning: custom element "x-a" doesn\'t declare any type ' | 376 'extensions. To fix this, either rewrite this tag as ' |
| 418 'extensions. To fix this, either rewrite this tag as ' | 377 '<x-a> or add \'extends="div"\' to ' |
| 419 '<x-a> or add \'extends="div"\' to ' | 378 'the custom element declaration. (lib/test.html 1 0)' |
| 420 'the custom element declaration. (lib/test.html 1 0)' | 379 ]); |
| 421 }); | |
| 422 | 380 |
| 423 _testLinter('used correctly (base tag)', { | 381 _testLinter('used correctly (base tag)', { |
| 424 'a|lib/b.html': ''' | 382 'a|lib/b.html': ''' |
| 425 <polymer-element name="x-a" extends="div"> | 383 <polymer-element name="x-a" extends="div"> |
| 426 </polymer-element> | 384 </polymer-element> |
| 427 '''.replaceAll(' ', ''), | 385 '''.replaceAll(' ', ''), |
| 428 'a|lib/test.html': ''' | 386 'a|lib/test.html': ''' |
| 429 <link rel="import" href="b.html"> | 387 <link rel="import" href="b.html"> |
| 430 <div is="x-a"></div> | 388 <div is="x-a"></div> |
| 431 '''.replaceAll(' ', ''), | 389 '''.replaceAll(' ', ''), |
| 432 }, { | 390 }, []); |
| 433 'a|lib/test.html.messages': '' | |
| 434 }); | |
| 435 | 391 |
| 436 _testLinter('used incorrectly (missing base tag)', { | 392 _testLinter('used incorrectly (missing base tag)', { |
| 437 'a|lib/b.html': ''' | 393 'a|lib/b.html': ''' |
| 438 <polymer-element name="x-a" extends="div"> | 394 <polymer-element name="x-a" extends="div"> |
| 439 </polymer-element> | 395 </polymer-element> |
| 440 '''.replaceAll(' ', ''), | 396 '''.replaceAll(' ', ''), |
| 441 'a|lib/test.html': ''' | 397 'a|lib/test.html': ''' |
| 442 <link rel="import" href="b.html"> | 398 <link rel="import" href="b.html"> |
| 443 <x-a></x-a> | 399 <x-a></x-a> |
| 444 '''.replaceAll(' ', ''), | 400 '''.replaceAll(' ', ''), |
| 445 }, { | 401 }, [ |
| 446 'a|lib/test.html.messages': '' | 402 'warning: custom element "x-a" extends from "div", but this tag ' |
| 447 'warning: custom element "x-a" extends from "div", but this tag ' | 403 'will not include the default properties of "div". To fix this, ' |
| 448 'will not include the default properties of "div". To fix this, ' | 404 'either write this tag as <div is="x-a"> or remove the "extends" ' |
| 449 'either write this tag as <div is="x-a"> or remove the "extends" ' | 405 'attribute from the custom element declaration. (lib/test.html 1 0)' |
| 450 'attribute from the custom element declaration. (lib/test.html 1 0)' | 406 ]); |
| 451 }); | |
| 452 | 407 |
| 453 _testLinter('used incorrectly (wrong base tag)', { | 408 _testLinter('used incorrectly (wrong base tag)', { |
| 454 'a|lib/b.html': ''' | 409 'a|lib/b.html': ''' |
| 455 <polymer-element name="x-a" extends="div"> | 410 <polymer-element name="x-a" extends="div"> |
| 456 </polymer-element> | 411 </polymer-element> |
| 457 '''.replaceAll(' ', ''), | 412 '''.replaceAll(' ', ''), |
| 458 'a|lib/test.html': ''' | 413 'a|lib/test.html': ''' |
| 459 <link rel="import" href="b.html"> | 414 <link rel="import" href="b.html"> |
| 460 <span is="x-a"></span> | 415 <span is="x-a"></span> |
| 461 '''.replaceAll(' ', ''), | 416 '''.replaceAll(' ', ''), |
| 462 }, { | 417 }, [ |
| 463 'a|lib/test.html.messages': '' | 418 'warning: custom element "x-a" extends from "div". Did you mean ' |
| 464 'warning: custom element "x-a" extends from "div". Did you mean ' | 419 'to write <div is="x-a">? (lib/test.html 1 0)' |
| 465 'to write <div is="x-a">? (lib/test.html 1 0)' | 420 ]); |
| 466 }); | |
| 467 | 421 |
| 468 _testLinter('used incorrectly (wrong base tag, transitive)', { | 422 _testLinter('used incorrectly (wrong base tag, transitive)', { |
| 469 'a|lib/c.html': ''' | 423 'a|lib/c.html': ''' |
| 470 <polymer-element name="x-c" extends="li"> | 424 <polymer-element name="x-c" extends="li"> |
| 471 </polymer-element> | 425 </polymer-element> |
| 472 <polymer-element name="x-b" extends="x-c"> | 426 <polymer-element name="x-b" extends="x-c"> |
| 473 </polymer-element> | 427 </polymer-element> |
| 474 '''.replaceAll(' ', ''), | 428 '''.replaceAll(' ', ''), |
| 475 'a|lib/b.html': ''' | 429 'a|lib/b.html': ''' |
| 476 <link rel="import" href="c.html"> | 430 <link rel="import" href="c.html"> |
| 477 <polymer-element name="x-a" extends="x-b"> | 431 <polymer-element name="x-a" extends="x-b"> |
| 478 </polymer-element> | 432 </polymer-element> |
| 479 '''.replaceAll(' ', ''), | 433 '''.replaceAll(' ', ''), |
| 480 'a|lib/test.html': ''' | 434 'a|lib/test.html': ''' |
| 481 <link rel="import" href="b.html"> | 435 <link rel="import" href="b.html"> |
| 482 <span is="x-a"></span> | 436 <span is="x-a"></span> |
| 483 '''.replaceAll(' ', ''), | 437 '''.replaceAll(' ', ''), |
| 484 }, { | 438 }, [ |
| 485 'a|lib/test.html.messages': '' | 439 'warning: custom element "x-a" extends from "li". Did you mean ' |
| 486 'warning: custom element "x-a" extends from "li". Did you mean ' | 440 'to write <li is="x-a">? (lib/test.html 1 0)' |
| 487 'to write <li is="x-a">? (lib/test.html 1 0)' | 441 ]); |
| 488 }); | |
| 489 }); | 442 }); |
| 490 | 443 |
| 491 group('custom attributes', () { | 444 group('custom attributes', () { |
| 492 _testLinter('foo-bar is no longer supported in attributes', { | 445 _testLinter('foo-bar is no longer supported in attributes', { |
| 493 'a|lib/test.html': '''<html><body> | 446 'a|lib/test.html': '''<html><body> |
| 494 <polymer-element name="x-a" attributes="foo-bar"> | 447 <polymer-element name="x-a" attributes="foo-bar"> |
| 495 </polymer-element> | 448 </polymer-element> |
| 496 '''.replaceAll(' ', ''), | 449 '''.replaceAll(' ', ''), |
| 497 }, { | 450 }, [ |
| 498 'a|lib/test.html.messages': | 451 'warning: PolymerElement no longer recognizes attribute names with ' |
| 499 'warning: PolymerElement no longer recognizes attribute names with ' | 452 'dashes such as "foo-bar". Use "fooBar" or "foobar" instead (both ' |
| 500 'dashes such as "foo-bar". Use "fooBar" or "foobar" instead (both ' | 453 'forms are equivalent in HTML). (lib/test.html 1 28)' |
| 501 'forms are equivalent in HTML). (lib/test.html 1 28)' | 454 ]); |
| 502 }); | |
| 503 }); | 455 }); |
| 504 } | 456 } |
| 505 | 457 |
| 506 _testLinter(String name, Map inputFiles, Map outputMessages) { | 458 _testLinter(String name, Map inputFiles, List outputMessages) { |
| 507 var linter = new Linter(new TransformOptions(), _testFormatter); | 459 var linter = new Linter(new TransformOptions()); |
| 508 var outputFiles = {}; | 460 var outputFiles = {}; |
| 509 inputFiles.forEach((k, v) => outputFiles[k] = v); | 461 inputFiles.forEach((k, v) => outputFiles[k] = v); |
| 510 outputMessages.forEach((k, v) => outputFiles[k] = v); | 462 testPhases(name, [[linter]], inputFiles, outputFiles, outputMessages); |
| 511 var keys = inputFiles.keys.toSet(); | |
| 512 keys.retainAll(outputMessages.keys); | |
| 513 expect(keys, isEmpty); | |
| 514 testPhases(name, [[linter]], inputFiles, outputFiles); | |
| 515 } | 463 } |
| 516 | |
| 517 | |
| 518 _testFormatter(String kind, String message, Span span) { | |
| 519 var formattedMessage = '$kind: $message'; | |
| 520 if (span != null) { | |
| 521 formattedMessage = '$formattedMessage ' | |
| 522 '(${span.sourceUrl} ${span.start.line} ${span.start.column})'; | |
| 523 } | |
| 524 return formattedMessage; | |
| 525 } | |
| OLD | NEW |