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