OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, 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.web.js_interop_test; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:html'; |
| 9 import 'dart:js'; |
| 10 import 'package:polymer/polymer.dart'; |
| 11 import 'package:polymer_interop/polymer_interop.dart'; |
| 12 import 'package:unittest/html_config.dart'; |
| 13 import 'package:unittest/unittest.dart'; |
| 14 |
| 15 @CustomTag('dart-element') |
| 16 class DartElement extends PolymerElement { |
| 17 DartElement.created() : super.created(); |
| 18 } |
| 19 |
| 20 @CustomTag('dart-element2') |
| 21 class DartElement2 extends PolymerElement { |
| 22 Element get quux => this.querySelector('.quux'); |
| 23 DartElement2.created() : super.created(); |
| 24 } |
| 25 |
| 26 @CustomTag('dart-element3') |
| 27 class DartElement3 extends PolymerElement { |
| 28 @observable var quux; |
| 29 DartElement3.created() : super.created(); |
| 30 |
| 31 domReady() { |
| 32 quux = new JsObject.jsify({'aDartMethod': (x) => 444 + x}); |
| 33 } |
| 34 } |
| 35 |
| 36 @CustomTag('dart-two-way') |
| 37 class DartTwoWay extends PolymerElement { |
| 38 @observable var twoWay = 40; |
| 39 DartTwoWay.created() : super.created(); |
| 40 } |
| 41 |
| 42 main() => initPolymer().then((zone) => zone.run(() { |
| 43 useHtmlConfiguration(); |
| 44 |
| 45 setUp(() => Polymer.onReady); |
| 46 |
| 47 test('dart-element upgraded', () { |
| 48 expect(querySelector('dart-element') is DartElement, true, |
| 49 reason: 'dart-element upgraded'); |
| 50 }); |
| 51 |
| 52 test('js-element in body', () => testInterop(querySelector('js-element'))); |
| 53 |
| 54 test('js-element in dart-element', () => testInterop( |
| 55 querySelector('dart-element').shadowRoot.querySelector('js-element'))); |
| 56 |
| 57 test('elements can be passed through Node.bind to JS', () { |
| 58 var text = querySelector('dart-element2').shadowRoot |
| 59 .querySelector('js-element2').shadowRoot.text; |
| 60 expect(text, 'QUX:123'); |
| 61 }); |
| 62 |
| 63 test('objects with functions can be passed through Node.bind to JS', () { |
| 64 var sr = querySelector('dart-element3').shadowRoot |
| 65 .querySelector('js-element3').shadowRoot; |
| 66 |
| 67 return new Future(() { |
| 68 expect(sr.text, 'js-element3[qux]:765'); |
| 69 }); |
| 70 }); |
| 71 |
| 72 test('two way bindings work', () { |
| 73 var dartElem = querySelector('dart-two-way'); |
| 74 var jsElem = dartElem.shadowRoot.querySelector('js-two-way'); |
| 75 var interop = new JsObject.fromBrowserObject(jsElem); |
| 76 |
| 77 return new Future(() { |
| 78 expect(jsElem.shadowRoot.text, 'FOOBAR:40'); |
| 79 |
| 80 expect(dartElem.twoWay, 40); |
| 81 expect(interop['foobar'], 40); |
| 82 |
| 83 interop.callMethod('aJsMethod', [2]); |
| 84 |
| 85 // Because Polymer.js two-way bindings are just a getter/setter pair |
| 86 // pointing at the original, we will see the new value immediately. |
| 87 expect(dartElem.twoWay, 42); |
| 88 |
| 89 expect(interop['foobar'], 42); |
| 90 |
| 91 // Text will update asynchronously |
| 92 expect(jsElem.shadowRoot.text, 'FOOBAR:40'); |
| 93 |
| 94 return _onTextChanged(jsElem.shadowRoot).then((_) { |
| 95 expect(jsElem.shadowRoot.text, 'FOOBAR:42'); |
| 96 }); |
| 97 }); |
| 98 }); |
| 99 })); |
| 100 |
| 101 Future<List<MutationRecord>> _onTextChanged(Node node) { |
| 102 var completer = new Completer(); |
| 103 new MutationObserver((mutations, observer) { |
| 104 observer.disconnect(); |
| 105 completer.complete(mutations); |
| 106 })..observe(node, characterData: true, subtree: true); |
| 107 return completer.future; |
| 108 } |
| 109 |
| 110 testInterop(jsElem) { |
| 111 expect(jsElem.shadowRoot.text, 'FOOBAR'); |
| 112 var interop = new JsObject.fromBrowserObject(jsElem); |
| 113 expect(interop['baz'], 42, reason: 'can read JS custom element properties'); |
| 114 |
| 115 jsElem.attributes['baz'] = '123'; |
| 116 return flush().then((_) { |
| 117 expect(interop['baz'], 123, reason: 'attribute reflected to property'); |
| 118 expect(jsElem.shadowRoot.text, 'FOOBAR', reason: 'text unchanged'); |
| 119 |
| 120 interop['baz'] = 777; |
| 121 return flush(); |
| 122 }).then((_) { |
| 123 expect(jsElem.attributes['baz'], '777', |
| 124 reason: 'property reflected to attribute'); |
| 125 |
| 126 expect(jsElem.shadowRoot.text, 'FOOBAR', reason: 'text unchanged'); |
| 127 |
| 128 interop.callMethod('aJsMethod', [123]); |
| 129 return flush(); |
| 130 }).then((_) { |
| 131 expect(jsElem.shadowRoot.text, '900', reason: 'text set by JS method'); |
| 132 expect(interop['baz'], 777, reason: 'unchanged'); |
| 133 }); |
| 134 } |
| 135 |
| 136 /// Calls Polymer.flush() to flush Polymer.js pending operations, e.g. |
| 137 /// dirty checking for data-bindings. |
| 138 Future flush() { |
| 139 PolymerJs.flush(); |
| 140 |
| 141 var completer = new Completer(); |
| 142 PolymerJs.endOfMicrotask(() => completer.complete()); |
| 143 return completer.future; |
| 144 } |
OLD | NEW |