Index: packages/polymer/test/build/linter_test.dart |
diff --git a/packages/polymer/test/build/linter_test.dart b/packages/polymer/test/build/linter_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0b7fe4c81f837bddc7402041491eb625d29fd6c9 |
--- /dev/null |
+++ b/packages/polymer/test/build/linter_test.dart |
@@ -0,0 +1,831 @@ |
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library polymer.test.linter_test; |
+ |
+import 'dart:convert'; |
+ |
+import 'package:polymer/src/build/common.dart'; |
+import 'package:polymer/src/build/linter.dart'; |
+import 'package:polymer/src/build/messages.dart'; |
+import 'package:unittest/unittest.dart'; |
+ |
+import 'common.dart'; |
+ |
+void main() { |
+ _testLinter('nothing to report', { |
+ 'a|lib/test.html': '<!DOCTYPE html><html></html>', |
+ }, []); |
+ |
+ group('must have proper initialization imports', () { |
+ _testLinter('nothing to report (no polymer use)', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('nothing to report (no polymer use with import)', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/polymer/polymer.html">' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('nothing to report (polymer used)', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/polymer/polymer.html">' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('nothing to report (polymer imported transitively)', { |
+ 'a|lib/lib.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="../../packages/polymer/polymer.html">', |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/a/lib.html">' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ test('usePolymerHtmlMessage looks right', () { |
+ _check(int i, String url) { |
+ expect(_usePolymerHtmlMessage(i), |
+ contains('<link rel="import" href="$url">')); |
+ } |
+ _check(0, 'packages/polymer/polymer.html'); |
+ _check(1, '../packages/polymer/polymer.html'); |
+ _check(2, '../../packages/polymer/polymer.html'); |
+ _check(3, '../../../packages/polymer/polymer.html'); |
+ }); |
+ |
+ _testLinter('missing polymer.html in web', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>\n' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${_usePolymerHtmlMessage(0)} ' |
+ '(web/test.html 1 0)', |
+ ]); |
+ |
+ _testLinter('missing polymer.html in web/foo', { |
+ 'a|web/foo/test.html': '<!DOCTYPE html><html>\n' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${_usePolymerHtmlMessage(1)} ' |
+ '(web/foo/test.html 1 0)', |
+ ]); |
+ |
+ _testLinter('missing polymer.html doesn\'t warn in lib', { |
+ 'a|lib/test.html': '<!DOCTYPE html><html>\n' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('missing polymer.html doesn\'t warn in lib/foo/bar', { |
+ 'a|lib/foo/bar/test.html': '<!DOCTYPE html><html>\n' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('missing Dart code', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/polymer/polymer.html">' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, ['warning: ${MISSING_INIT_POLYMER.snippet}',]); |
+ |
+ _testLinter('nothing to report, experimental with no Dart code', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" ' |
+ 'href="packages/polymer/polymer_experimental.html">' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, []); |
+ |
+ _testLinter('experimental cannot have Dart code in main document', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" ' |
+ 'href="packages/polymer/polymer_experimental.html">\n' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${NO_DART_SCRIPT_AND_EXPERIMENTAL.snippet} ' |
+ '(web/test.html 1 0)', |
+ ]); |
+ |
+ _testLinter('missing Dart code and polymer.html', { |
+ 'a|web/test.html': '<!DOCTYPE html><html></html>', |
+ }, ['warning: ${MISSING_INIT_POLYMER.snippet}',]); |
+ |
+ _testLinter('dart_support unnecessary', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<script src="packages/web_components/dart_support.js"></script>' |
+ '<link rel="import" href="../../packages/polymer/polymer.html">' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${DART_SUPPORT_NO_LONGER_REQUIRED.snippet} ' |
+ '(web/test.html 0 21)' |
+ ]); |
+ |
+ _testLinter('webcomponents unnecessary', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '$WEB_COMPONENTS_JS_TAG' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${WEB_COMPONENTS_NO_LONGER_REQUIRED.snippet} ' |
+ '(web/test.html 0 21)' |
+ ]); |
+ |
+ _testLinter('platform.js -> webcomponents.js', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '$PLATFORM_JS_TAG' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '</html>', |
+ }, [ |
+ 'warning: ${PLATFORM_JS_RENAMED.snippet} ' |
+ '(web/test.html 0 21)' |
+ ]); |
+ }); |
+ |
+ group('single script tag per document', () { |
+ _testLinter('two top-level tags', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/polymer/polymer.html">' |
+ '<script type="application/dart" src="a.dart">' |
+ '</script>\n' |
+ '<script type="application/dart" src="b.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>', |
+ }, ['warning: ${ONLY_ONE_TAG.snippet} (web/test.html 1 0)',]); |
+ |
+ _testLinter('two top-level tags, non entrypoint', { |
+ 'a|lib/test.html': '<!DOCTYPE html><html>' |
+ '<script type="application/dart" src="a.dart">' |
+ '</script>\n' |
+ '<script type="application/dart" src="b.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ }, ['warning: ${ONLY_ONE_TAG.snippet} (lib/test.html 1 0)',]); |
+ |
+ _testLinter('tags inside elements', { |
+ 'a|web/test.html': '<!DOCTYPE html><html>' |
+ '<link rel="import" href="packages/polymer/polymer.html">' |
+ '<polymer-element name="x-a">' |
+ '<script type="application/dart" src="a.dart">' |
+ '</script>' |
+ '</polymer-element>\n' |
+ '<script type="application/dart" src="b.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>', |
+ }, ['warning: ${ONLY_ONE_TAG.snippet} (web/test.html 1 0)',]); |
+ }); |
+ |
+ group('doctype warning', () { |
+ _testLinter('in web', {'a|web/test.html': '<html></html>',}, [ |
+ 'warning: (from html) Unexpected start tag (html). ' |
+ 'Expected DOCTYPE. (web/test.html 0 0)', |
+ 'warning: ${MISSING_INIT_POLYMER.snippet}', |
+ ]); |
+ |
+ _testLinter('in lib', {'a|lib/test.html': '<html></html>',}, []); |
+ }); |
+ |
+ group('duplicate polymer-elements,', () { |
+ _testLinter('same file', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ''}).snippet} (lib/test.html 2 0)', |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ' (second definition).'}).snippet} ' |
+ '(lib/test.html 3 0)', |
+ ]); |
+ |
+ _testLinter('other file', { |
+ 'a|lib/b.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="b.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ''}).snippet} (lib/b.html 2 0)', |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ' (second definition).'}).snippet} ' |
+ '(lib/test.html 2 0)', |
+ ]); |
+ |
+ _testLinter('non existing file', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <link rel="import" href="b.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${IMPORT_NOT_FOUND.create( |
+ {'path': 'lib/b.html', 'package': 'a'}).snippet} ' |
+ '(lib/test.html 2 0)' |
+ ]); |
+ |
+ _testLinter('other package', { |
+ 'b|lib/b.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/b/b.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ''}).snippet} (package:b/b.html 2 0)', |
+ 'warning: ${DUPLICATE_DEFINITION.create( |
+ {'name': 'x-a', 'second': ' (second definition).'}).snippet} ' |
+ '(lib/test.html 2 0)', |
+ ]); |
+ }); |
+ |
+ _testLinter('bad link-rel tag (href missing)', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import"> |
+ <link rel="stylesheet"> |
+ <link rel="foo"> |
+ <link rel="import" href=""> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${MISSING_HREF.create({'rel': 'import'}).snippet} ' |
+ '(lib/test.html 1 0)', |
+ 'warning: ${MISSING_HREF.create({'rel': 'stylesheet'}).snippet} ' |
+ '(lib/test.html 2 0)', |
+ 'warning: ${MISSING_HREF.create({'rel': 'import'}).snippet} ' |
+ '(lib/test.html 4 0)', |
+ ]); |
+ |
+ _testLinter('<element> is not supported', { |
+ 'a|lib/test.html': '''<html> |
+ <element name="x-a"></element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['warning: ${ELEMENT_DEPRECATED_EONS_AGO.snippet} (lib/test.html 1 0)']); |
+ |
+ _testLinter('do not nest <polymer-element>', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"> |
+ <template><div> |
+ <polymer-element name="b"></polymer-element> |
+ </div></template> |
+ </polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['error: ${NESTED_POLYMER_ELEMENT.snippet} (lib/test.html 4 4)']); |
+ |
+ _testLinter('do put import inside <polymer-element>', { |
+ 'a|lib/b.html': '<html></html>', |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"> |
+ <link rel="import" href="b.html"> |
+ <template><div> |
+ </div></template> |
+ </polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['error: ${NO_IMPORT_WITHIN_ELEMENT.snippet} (lib/test.html 3 2)']); |
+ |
+ _testLinter('need a name for <polymer-element>', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['error: ${MISSING_TAG_NAME.snippet} (lib/test.html 2 0)']); |
+ |
+ _testLinter('name for <polymer-element> should have dashes', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="a"></polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'error: ${INVALID_TAG_NAME.create({'name': 'a'}).snippet} ' |
+ '(lib/test.html 2 0)' |
+ ]); |
+ |
+ _testLinter('extend is a valid element or existing tag', { |
+ 'a|web/test.html': '''<!DOCTYPE html><html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" extends="li"></polymer-element> |
+ <script type="application/dart"> |
+ export 'package:polymer/init.dart'; |
+ </script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('extend is a valid element or existing tag', { |
+ 'a|web/test.html': '''<!DOCTYPE html><html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" extends="x-b"></polymer-element> |
+ <script type="application/dart"> |
+ export 'package:polymer/init.dart'; |
+ </script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${CUSTOM_ELEMENT_NOT_FOUND.create({'tag': 'x-b'}).snippet} ' |
+ '(web/test.html 2 0)' |
+ ]); |
+ |
+ group('script type matches code', () { |
+ _testLinter('top-level, .dart url', { |
+ 'a|lib/test.html': '''<html> |
+ <script src="foo.dart"></script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: Wrong script type, expected type="application/dart".' |
+ ' (lib/test.html 1 0)' |
+ ]); |
+ |
+ _testLinter('in polymer-element, .dart url', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"> |
+ <script src="foo.dart"></script> |
+ </polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['warning: ${EXPECTED_DART_MIME_TYPE.snippet} (lib/test.html 3 0)']); |
+ |
+ _testLinter('in polymer-element, .js url', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"> |
+ <script src="foo.js"></script> |
+ </polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('in polymer-element, inlined', { |
+ 'a|lib/test.html': '''<html> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"> |
+ <script>foo...</script> |
+ </polymer-element> |
+ </html>'''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('top-level, dart type & .dart url', { |
+ 'a|lib/test.html': '''<html> |
+ <script type="application/dart" src="foo.dart"></script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('top-level, dart type & .js url', { |
+ 'a|lib/test.html': '''<html> |
+ <script type="application/dart" src="foo.js"></script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['warning: ${EXPECTED_DART_EXTENSION.snippet} (lib/test.html 1 0)']); |
+ }); |
+ |
+ _testLinter('script tags should have at least src url or inline code', { |
+ 'a|lib/test.html': '''<html> |
+ <script type="application/dart"></script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, ['warning: ${SCRIPT_TAG_SEEMS_EMPTY.snippet} (lib/test.html 1 0)']); |
+ |
+ _testLinter('script tags should have only src url or inline code', { |
+ 'a|lib/test.html': '''<html> |
+ <script type="application/dart" src="foo.dart">more</script> |
+ </html>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${FOUND_BOTH_SCRIPT_SRC_AND_TEXT.snippet} (lib/test.html 1 0)' |
+ ]); |
+ |
+ group('event handlers', () { |
+ _testLinter('no longer warn about inline onfoo (Javascript)', { |
+ 'a|lib/test.html': '''<html><body> |
+ <div onfoo="something"></div> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('no longer warn about on-foo for auto-binding templates', { |
+ 'a|lib/test.html': '''<html><body> |
+ <template is="auto-binding-dart"> |
+ <div on-foo="{{something}}"></div> |
+ <template> |
+ <div>foo</div> |
+ </template> |
+ <div on-foo="{{something}}"></div> |
+ </template> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('on-foo is only supported in polymer elements', { |
+ 'a|lib/test.html': '''<html><body> |
+ <div on-foo="{{something}}"></div> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${EVENT_HANDLERS_ONLY_WITHIN_POLYMER.snippet} ' |
+ '(lib/test.html 1 5)' |
+ ]); |
+ |
+ _testLinter('on-foo uses the {{ binding }} syntax', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"><div on-foo="bar"></div> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${INVALID_EVENT_HANDLER_BODY.create( |
+ {'value': 'bar', 'name': 'on-foo'}).snippet} (lib/test.html 2 33)' |
+ ]); |
+ |
+ _testLinter('on-foo is not an expression', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"><div on-foo="{{bar()}}"></div> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${INVALID_EVENT_HANDLER_BODY.create( |
+ {'value': '{{bar()}}', 'name': 'on-foo'}).snippet} ' |
+ '(lib/test.html 2 33)' |
+ ]); |
+ |
+ _testLinter('on-foo can\'t be empty', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"><div on-foo="{{}}"></div> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${INVALID_EVENT_HANDLER_BODY.create( |
+ {'value': '{{}}', 'name': 'on-foo'}).snippet} (lib/test.html 2 33)' |
+ ]); |
+ |
+ _testLinter('on-foo can\'t be just space', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"><div on-foo="{{ }}"></div> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${INVALID_EVENT_HANDLER_BODY.create( |
+ {'value': '{{ }}', 'name': 'on-foo'}).snippet} (lib/test.html 2 33)' |
+ ]); |
+ |
+ _testLinter('on-foo-bar is supported as a custom event name', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"><div on-foo-bar="{{quux}}"></div> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ }); |
+ |
+ group('using custom tags', () { |
+ _testLinter('tag exists (x-tag)', { |
+ 'a|web/test.html': '''<!DOCTYPE html> |
+ <x-foo></x-foo> |
+ <script type="application/dart"> |
+ export 'package:polymer/init.dart'; |
+ </script> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${CUSTOM_ELEMENT_NOT_FOUND.create({'tag': 'x-foo'}).snippet} ' |
+ '(web/test.html 1 0)' |
+ ]); |
+ |
+ _testLinter('tag exists (type extension)', { |
+ 'a|web/test.html': '''<!DOCTYPE html> |
+ <div is="x-foo"></div> |
+ <script type="application/dart"> |
+ export 'package:polymer/init.dart'; |
+ </script>'''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${CUSTOM_ELEMENT_NOT_FOUND.create({'tag': 'x-foo'}).snippet} ' |
+ '(web/test.html 1 0)', |
+ ]); |
+ |
+ _testLinter('tag exists (internally defined in code)', { |
+ 'a|lib/test.html': '<div is="auto-binding-dart"></div>', |
+ }, []); |
+ |
+ _testLinter('used correctly (no base tag)', { |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ <x-a></x-a> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('used incorrectly (no base tag)', { |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element> |
+ <div is="x-a"></div> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${BAD_INSTANTIATION_BOGUS_BASE_TAG.create( |
+ {'tag': 'x-a', 'base': 'div'}).snippet} (lib/test.html 2 0)' |
+ ]); |
+ |
+ _testLinter('used incorrectly, imported def (no base tag)', { |
+ 'a|lib/b.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a"></polymer-element>''', |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="b.html"> |
+ <div is="x-a"></div> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${BAD_INSTANTIATION_BOGUS_BASE_TAG.create( |
+ {'tag': 'x-a', 'base': 'div'}).snippet} (lib/test.html 1 0)' |
+ ]); |
+ |
+ _testLinter('used correctly (base tag)', { |
+ 'a|lib/b.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" extends="div"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="b.html"> |
+ <div is="x-a"></div> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ _testLinter('used incorrectly (missing base tag)', { |
+ 'a|lib/b.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" extends="div"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="b.html"> |
+ <x-a></x-a> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${BAD_INSTANTIATION_MISSING_BASE_TAG.create( |
+ {'tag': 'x-a', 'base': 'div'}).snippet} (lib/test.html 1 0)' |
+ ]); |
+ |
+ _testLinter('used incorrectly (wrong base tag)', { |
+ 'a|lib/b.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" extends="div"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="b.html"> |
+ <span is="x-a"></span> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${BAD_INSTANTIATION_WRONG_BASE_TAG.create( |
+ {'tag': 'x-a', 'base': 'div'}).snippet} (lib/test.html 1 0)' |
+ ]); |
+ |
+ _testLinter('used incorrectly (wrong base tag, transitive)', { |
+ 'a|lib/c.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-c" extends="li"> |
+ </polymer-element> |
+ <polymer-element name="x-b" extends="x-c"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ 'a|lib/b.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <link rel="import" href="c.html"> |
+ <polymer-element name="x-a" extends="x-b"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ 'a|lib/test.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <link rel="import" href="b.html"> |
+ <span is="x-a"></span> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${BAD_INSTANTIATION_WRONG_BASE_TAG.create( |
+ {'tag': 'x-a', 'base': 'li'}).snippet} (lib/test.html 2 0)' |
+ ]); |
+ |
+ _testLinter('FOUC warning works', { |
+ 'a|web/a.html': ''' |
+ <!DOCTYPE html> |
+ <html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element>hello!</my-element> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ 'a|web/b.html': ''' |
+ <!DOCTYPE html> |
+ <html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <div><my-element>hello!</my-element></div> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ 'a|web/c.html': ''' |
+ <!DOCTYPE html> |
+ <html unresolved><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element>hello!</my-element> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''' |
+ }, [ |
+ 'warning: ${POSSIBLE_FUOC.snippet} (web/a.html 4 14)', |
+ 'warning: ${POSSIBLE_FUOC.snippet} (web/b.html 4 19)', |
+ 'warning: ${POSSIBLE_FUOC.snippet} (web/c.html 4 14)', |
+ ]); |
+ |
+ _testLinter('FOUC, no false positives.', { |
+ // Parent has unresolved attribute. |
+ 'a|web/a.html': ''' |
+ <!DOCTYPE html> |
+ <html><body> |
+ <div unresolved> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element>hello!</my-element> |
+ </div> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ // Body has unresolved attribute. |
+ 'a|web/b.html': ''' |
+ <!DOCTYPE html> |
+ <html><body unresolved> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element>hello!</my-element> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ // Inside polymer-element tags its fine. |
+ 'a|web/c.html': ''' |
+ <!DOCTYPE html> |
+ <html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <polymer-element name="foo-element"> |
+ <template><my-element>hello!</my-element></template> |
+ </polymer-element> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ // Empty custom elements are fine. |
+ 'a|web/d.html': ''' |
+ <!DOCTYPE html> |
+ <html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element></my-element> |
+ <script type="application/dart"> |
+ export "package:polymer/init.dart"; |
+ </script> |
+ </body></html> |
+ ''', |
+ // Entry points only! |
+ 'a|lib/a.html': ''' |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="my-element" noscript></polymer-element> |
+ <my-element>hello!</my-element> |
+ ''', |
+ }, []); |
+ }); |
+ |
+ group('custom attributes', () { |
+ _testLinter('foo-bar is no longer supported in attributes', { |
+ 'a|lib/test.html': '''<html><body> |
+ <link rel="import" href="../../packages/polymer/polymer.html"> |
+ <polymer-element name="x-a" attributes="foo-bar"> |
+ </polymer-element> |
+ '''.replaceAll(' ', ''), |
+ }, [ |
+ 'warning: ${NO_DASHES_IN_CUSTOM_ATTRIBUTES.create( |
+ {'name': 'foo-bar', 'alternative': '"fooBar" or "foobar"'}) |
+ .snippet} (lib/test.html 2 28)' |
+ ]); |
+ }); |
+ |
+ _testLinter("namespaced attributes don't cause an internal error", { |
+ 'a|lib/test.html': '''<html><body> |
+ <svg xmlns="http://www.w3.org/2000/svg" width="520" height="350"> |
+ </svg> |
+ '''.replaceAll(' ', ''), |
+ }, []); |
+ |
+ group('output logs to file', () { |
+ final outputLogsPhases = [ |
+ [ |
+ new Linter(new TransformOptions( |
+ injectBuildLogsInOutput: true, releaseMode: false)) |
+ ] |
+ ]; |
+ |
+ testPhases("logs are output to file", outputLogsPhases, { |
+ 'a|web/test.html': '<!DOCTYPE html><html>\n' |
+ '<polymer-element name="x-a"></polymer-element>' |
+ '<script type="application/dart" src="foo.dart">' |
+ '</script>' |
+ '<script src="packages/browser/dart.js"></script>' |
+ '</html>', |
+ }, { |
+ 'a|web/test.html._buildLogs.1': '{"polymer#3":[{' |
+ '"level":"Warning",' |
+ '"message":{' |
+ '"id":"polymer#3",' |
+ '"snippet":"${_usePolymerHtmlMessage(0).replaceAll('"','\\"')}"' |
+ '},' |
+ '"span":{' |
+ '"start":{' |
+ '"url":"web/test.html",' |
+ '"offset":22,' |
+ '"line":1,' |
+ '"column":0' |
+ '},' |
+ '"end":{' |
+ '"url":"web/test.html",' |
+ '"offset":50,' |
+ '"line":1,' |
+ '"column":28' |
+ '},' |
+ '"text":"<polymer-element name=\\"x-a\\">"' |
+ '}' |
+ '}]}', |
+ }, [ |
+ // Logs should still make it to barback too. |
+ 'warning: ${_usePolymerHtmlMessage(0)} (web/test.html 1 0)', |
+ ]); |
+ }); |
+} |
+ |
+_usePolymerHtmlMessage(int i) { |
+ var prefix = '../' * i; |
+ return USE_POLYMER_HTML.create({'reachOutPrefix': prefix}).snippet; |
+} |
+ |
+_testLinter(String name, Map inputFiles, List outputMessages, |
+ [bool solo = false]) { |
+ var outputFiles = {}; |
+ if (outputMessages.every((m) => m.startsWith('warning:'))) { |
+ inputFiles.forEach((k, v) => outputFiles[k] = v); |
+ } |
+ if (outputMessages.isEmpty) { |
+ var linter = new Linter(new TransformOptions()); |
+ testPhases(name, [[linter]], inputFiles, outputFiles, outputMessages, solo); |
+ } else { |
+ testLogOutput((options) => new Linter(options), name, inputFiles, |
+ outputFiles, outputMessages, solo); |
+ } |
+} |