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 created_callback_test; | 5 library created_callback_test; |
6 import 'package:unittest/unittest.dart'; | 6 import 'package:unittest/unittest.dart'; |
7 import 'package:unittest/html_config.dart'; | 7 import 'package:unittest/html_config.dart'; |
8 import 'dart:html'; | 8 import 'dart:html'; |
9 import 'dart:js' as js; | |
9 import '../utils.dart'; | 10 import '../utils.dart'; |
10 | 11 |
11 class A extends HtmlElement { | 12 class A extends HtmlElement { |
12 static final tag = 'x-a'; | 13 static final tag = 'x-a'; |
13 factory A() => new Element.tag(tag); | 14 factory A() => new Element.tag(tag); |
15 A.created() : super.created(); | |
14 | 16 |
15 static int createdInvocations = 0; | 17 static int createdInvocations = 0; |
16 | 18 |
17 void created() { | 19 void createdCallback() { |
18 createdInvocations++; | 20 createdInvocations++; |
19 } | 21 } |
20 } | 22 } |
21 | 23 |
22 class B extends HtmlElement { | 24 class B extends HtmlElement { |
23 static final tag = 'x-b'; | 25 static final tag = 'x-b'; |
24 factory B() => new Element.tag(tag); | 26 factory B() => new Element.tag(tag); |
27 B.created() : super.created(); | |
25 } | 28 } |
26 | 29 |
27 class C extends HtmlElement { | 30 class C extends HtmlElement { |
28 static final tag = 'x-c'; | 31 static final tag = 'x-c'; |
29 factory C() => new Element.tag(tag); | 32 factory C() => new Element.tag(tag); |
33 C.created() : super.created(); | |
30 | 34 |
31 static int createdInvocations = 0; | 35 static int createdInvocations = 0; |
32 static var div; | 36 static var div; |
33 | 37 |
34 void created() { | 38 void createdCallback() { |
35 createdInvocations++; | 39 createdInvocations++; |
36 | 40 |
37 if (this.id != 'u') { | 41 if (this.id != 'u') { |
38 return; | 42 return; |
39 } | 43 } |
40 | 44 |
41 var t = div.query('#t'); | 45 var t = div.query('#t'); |
42 var v = div.query('#v'); | 46 var v = div.query('#v'); |
43 var w = div.query('#w'); | 47 var w = div.query('#w'); |
44 | 48 |
45 expect(query('x-b:not(:unresolved)'), this); | 49 expect(query('x-b:not(:unresolved)'), this); |
46 expect(queryAll(':unresolved'), [v, w]); | 50 expect(queryAll(':unresolved'), [v, w]); |
47 | 51 |
48 // As per: | 52 // As per: |
49 // http://www.w3.org/TR/2013/WD-custom-elements-20130514/#serializing-and-pa rsing | 53 // http://www.w3.org/TR/2013/WD-custom-elements-20130514/#serializing-and-pa rsing |
50 // creation order is t, u, v, w (postorder). | 54 // creation order is t, u, v, w (postorder). |
51 expect(t is C, isTrue); | 55 expect(t is C, isTrue); |
52 // Note, this is different from JavaScript where this would be false. | 56 // Note, this is different from JavaScript where this would be false. |
53 expect(v is C, isTrue); | 57 expect(v is C, isTrue); |
54 } | 58 } |
55 } | 59 } |
56 | 60 |
57 main() { | 61 main() { |
58 useHtmlConfiguration(); | 62 useHtmlConfiguration(); |
59 | 63 |
60 // Adapted from Blink's | 64 // Adapted from Blink's |
61 // fast/dom/custom/created-callback test. | 65 // fast/dom/custom/created-callback test. |
62 | 66 |
63 setUp(loadPolyfills); | 67 var registered = false; |
68 setUp(() { | |
69 return loadPolyfills().then((_) { | |
70 if (!registered) { | |
71 registered = true; | |
72 document.register(B.tag, B); | |
73 document.register(C.tag, C); | |
74 ErrorConstructorElement.register(); | |
75 } | |
76 }); | |
77 }); | |
64 | 78 |
65 test('transfer created callback', () { | 79 test('transfer created callback', () { |
66 document.register(A.tag, A); | 80 document.register(A.tag, A); |
67 var x = new A(); | 81 var x = new A(); |
68 expect(A.createdInvocations, 1); | 82 expect(A.createdInvocations, 1); |
69 }); | 83 }); |
70 | 84 |
71 test(':unresolved and created callback timing', () { | 85 test('unresolved and created callback timing', () { |
72 document.register(B.tag, B); | |
73 document.register(C.tag, C); | |
74 | |
75 var div = new DivElement(); | 86 var div = new DivElement(); |
76 C.div = div; | 87 C.div = div; |
77 div.setInnerHtml(""" | 88 div.setInnerHtml(""" |
78 <x-c id="t"></x-c> | 89 <x-c id="t"></x-c> |
79 <x-b id="u"></x-b> | 90 <x-b id="u"></x-b> |
80 <x-c id="v"></x-c> | 91 <x-c id="v"></x-c> |
81 <x-b id="w"></x-b> | 92 <x-b id="w"></x-b> |
82 """, treeSanitizer: new NullTreeSanitizer()); | 93 """, treeSanitizer: new NullTreeSanitizer()); |
83 | 94 |
84 Platform.upgradeCustomElements(div); | 95 Platform.upgradeCustomElements(div); |
85 | 96 |
86 expect(C.createdInvocations, 2); | 97 expect(C.createdInvocations, 2); |
87 expect(div.query('#w') is B, isTrue); | 98 expect(div.query('#w') is B, isTrue); |
88 }); | 99 }); |
89 | 100 |
101 test('nesting of constructors', NestedElement.test); | |
102 | |
103 test('access while upgrading gets unupgraded element', | |
104 AccessWhileUpgradingElement.test); | |
105 | |
106 test('cannot call created constructor', () { | |
107 expect(() { | |
108 new B.created(); | |
109 }, throws); | |
110 }); | |
111 | |
112 test('cannot register without created', () { | |
113 expect(() { | |
114 document.register(MissingCreatedElement.tag, MissingCreatedElement); | |
115 }, throws); | |
116 }); | |
117 | |
118 test('throw on createElement does not upgrade', () { | |
119 ErrorConstructorElement.callCount = 0; | |
120 | |
121 var e; | |
122 expectGlobalError(() { | |
123 e = new Element.tag(ErrorConstructorElement.tag); | |
124 }); | |
125 expect(ErrorConstructorElement.callCount, 1); | |
126 expect(e is HtmlElement, isTrue); | |
127 expect(e is ErrorConstructorElement, isFalse); | |
128 | |
129 var dummy = new DivElement(); | |
130 dummy.append(e); | |
131 e = dummy.firstChild; | |
132 expect(ErrorConstructorElement.callCount, 1); | |
133 }); | |
134 | |
135 test('throw on innerHtml does not upgrade', () { | |
136 ErrorConstructorElement.callCount = 0; | |
137 | |
138 var dummy = new DivElement(); | |
139 var tag = ErrorConstructorElement.tag; | |
140 expectGlobalError(() { | |
141 dummy.setInnerHtml('<$tag></$tag>', | |
142 treeSanitizer: new NullTreeSanitizer()); | |
143 }); | |
144 | |
145 expect(ErrorConstructorElement.callCount, 1); | |
146 | |
147 var e = dummy.firstChild; | |
148 // Accessing should not re-run the constructor. | |
149 expect(ErrorConstructorElement.callCount, 1); | |
150 expect(e is HtmlElement, isTrue); | |
151 expect(e is ErrorConstructorElement, isFalse); | |
152 }); | |
153 | |
154 // Issue - 13711 Need to fix the handling of the created constructor. | |
155 // test('created cannot be called from nested constructor', | |
156 // NestedCreatedConstructorElement.test); | |
157 | |
158 | |
90 // TODO(vsm): Port additional test from upstream here: | 159 // TODO(vsm): Port additional test from upstream here: |
91 // http://src.chromium.org/viewvc/blink/trunk/LayoutTests/fast/dom/custom/crea ted-callback.html?r1=156141&r2=156185 | 160 // http://src.chromium.org/viewvc/blink/trunk/LayoutTests/fast/dom/custom/crea ted-callback.html?r1=156141&r2=156185 |
92 } | 161 } |
162 | |
163 | |
164 class NestedElement extends HtmlElement { | |
165 static final tag = 'x-nested'; | |
166 | |
167 final Element b = new B(); | |
168 | |
169 factory NestedElement() => new Element.tag(tag); | |
170 NestedElement.created() : super.created(); | |
171 | |
172 static void register() { | |
173 document.register(tag, NestedElement); | |
174 } | |
175 | |
176 static void test() { | |
177 register(); | |
178 | |
179 var e = new NestedElement(); | |
180 expect(e.b, isNotNull); | |
181 expect(e.b is B, isTrue); | |
182 expect(e is NestedElement, isTrue); | |
183 } | |
184 } | |
185 | |
186 | |
187 class AccessWhileUpgradingElement extends HtmlElement { | |
188 static final tag = 'x-access-while-upgrading'; | |
189 | |
190 static Element upgradingContext; | |
191 static Element upgradingContextChild; | |
192 | |
193 final foo = runInitializerCode(); | |
194 | |
195 factory AccessWhileUpgradingElement() => new Element.tag(tag); | |
196 AccessWhileUpgradingElement.created() : super.created(); | |
197 | |
198 static runInitializerCode() { | |
199 upgradingContextChild = upgradingContext.firstChild; | |
200 | |
201 return 666; | |
202 } | |
203 | |
204 static void register() { | |
205 document.register(tag, AccessWhileUpgradingElement); | |
206 } | |
207 | |
208 static void test() { | |
209 register(); | |
210 | |
211 upgradingContext = new DivElement(); | |
212 upgradingContext.setInnerHtml('<$tag></$tag>', | |
213 treeSanitizer: new NullTreeSanitizer()); | |
214 var child = upgradingContext.firstChild; | |
215 | |
216 expect(child.foo, 666); | |
217 expect(upgradingContextChild is HTMLElement, isTrue); | |
218 expect(upgradingContextChild is AccessWhileUpgradingElement, isFalse, | |
219 reason: 'Elements accessed while upgrading should not be upgraded.'); | |
220 } | |
221 } | |
222 | |
223 class MissingCreatedElement extends HtmlElement { | |
224 static final tag = 'x-missing-created'; | |
225 | |
226 factory MissingCreatedElement() => new Element.tag(tag); | |
227 } | |
228 | |
229 class ErrorConstructorElement extends HtmlElement { | |
230 static final tag = 'x-throws-in-constructor'; | |
231 static int callCount = 0; | |
232 | |
233 factory ErrorConstructorElement() => new Element.tag(tag); | |
234 | |
235 ErrorConstructorElement.created() : super.created() { | |
236 ++callCount; | |
237 throw new Exception('Just messin with ya'); | |
238 } | |
239 | |
240 static void register() { | |
241 document.register(tag, ErrorConstructorElement); | |
242 } | |
243 } | |
244 /* | |
vsm
2013/10/01 16:58:01
Does this need to be commented out?
blois
2013/10/01 20:37:08
Done.
| |
245 class NestedCreatedConstructorElement extends HtmlElement { | |
246 static final tag = 'x-nested-created-constructor'; | |
247 | |
248 // Should not be able to call this here. | |
249 final B b = constructB(); | |
250 static B constructedB; | |
251 | |
252 factory NestedCreatedConstructorElement() => new Element.tag(tag); | |
253 NestedCreatedConstructorElement.created() : super.created(); | |
254 | |
255 static void register() { | |
256 document.register(tag, NestedCreatedConstructorElement); | |
257 } | |
258 | |
259 // Try to run the created constructor, and record the results. | |
260 static constructB() { | |
261 // This should throw an exception. | |
262 constructedB = new B.created(); | |
263 return constructedB; | |
264 } | |
265 | |
266 static void test() { | |
267 register(); | |
268 | |
269 // Exception should have occurred on upgrade. | |
270 var e = new Element.tag(tag); | |
271 expect(e is NestedCreatedConstructorElement, isFalse); | |
272 expect(e is HtmlElement, isTrue); | |
273 // Should not have been set. | |
274 expect(constructedB, isNull); | |
275 } | |
276 } | |
277 */ | |
278 | |
279 void expectGlobalError(Function test) { | |
280 js.context['testExpectsGlobalError'] = true; | |
281 try { | |
282 test(); | |
283 } catch(e) { | |
284 rethrow; | |
285 } finally { | |
286 js.context['testExpectsGlobalError'] = false; | |
287 } | |
288 var errors = js.context['testSuppressedGlobalErrors']; | |
289 expect(errors['length'], 1); | |
290 // Clear out the errors; | |
291 js.context['testSuppressedGlobalErrors']['length'] = 0; | |
292 } | |
OLD | NEW |