Chromium Code Reviews| 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 |