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 |