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 entered_left_view_test; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:html'; |
| 9 import 'dart:js' as js; |
| 10 import 'package:unittest/html_individual_config.dart'; |
| 11 import 'package:unittest/unittest.dart'; |
| 12 import '../utils.dart'; |
| 13 |
| 14 var invocations = []; |
| 15 class Foo extends HtmlElement { |
| 16 factory Foo() => null; |
| 17 Foo.created() : super.created() { |
| 18 invocations.add('created'); |
| 19 } |
| 20 |
| 21 void attached() { |
| 22 invocations.add('attached'); |
| 23 } |
| 24 |
| 25 void enteredView() { |
| 26 // Deprecated name. Should never be called since we override "attached". |
| 27 invocations.add('enteredView'); |
| 28 } |
| 29 |
| 30 void detached() { |
| 31 invocations.add('detached'); |
| 32 } |
| 33 |
| 34 void leftView() { |
| 35 // Deprecated name. Should never be called since we override "detached". |
| 36 invocations.add('leftView'); |
| 37 } |
| 38 |
| 39 void attributeChanged(String name, String oldValue, String newValue) { |
| 40 invocations.add('attribute changed'); |
| 41 } |
| 42 } |
| 43 |
| 44 |
| 45 // Test that the deprecated callbacks still work. |
| 46 class FooOldCallbacks extends HtmlElement { |
| 47 factory FooOldCallbacks() => null; |
| 48 FooOldCallbacks.created() : super.created() { |
| 49 invocations.add('created'); |
| 50 } |
| 51 |
| 52 void enteredView() { |
| 53 invocations.add('enteredView'); |
| 54 } |
| 55 |
| 56 void leftView() { |
| 57 invocations.add('leftView'); |
| 58 } |
| 59 |
| 60 void attributeChanged(String name, String oldValue, String newValue) { |
| 61 invocations.add('attribute changed'); |
| 62 } |
| 63 } |
| 64 |
| 65 main() { |
| 66 useHtmlIndividualConfiguration(); |
| 67 |
| 68 // Adapted from Blink's |
| 69 // fast/dom/custom/attached-detached-document.html test. |
| 70 |
| 71 var docA = document; |
| 72 var docB = document.implementation.createHtmlDocument(''); |
| 73 |
| 74 var nullSanitizer = new NullTreeSanitizer(); |
| 75 |
| 76 var registeredTypes = false; |
| 77 setUp(() => customElementsReady.then((_) { |
| 78 if (registeredTypes) return; |
| 79 registeredTypes = true; |
| 80 document.registerElement('x-a', Foo); |
| 81 document.registerElement('x-a-old', FooOldCallbacks); |
| 82 })); |
| 83 |
| 84 group('standard_events', () { |
| 85 var a; |
| 86 setUp(() { |
| 87 invocations = []; |
| 88 }); |
| 89 |
| 90 test('Created', () { |
| 91 a = new Element.tag('x-a'); |
| 92 expect(invocations, ['created']); |
| 93 }); |
| 94 |
| 95 test('attached', () { |
| 96 document.body.append(a); |
| 97 customElementsTakeRecords(); |
| 98 expect(invocations, ['attached']); |
| 99 }); |
| 100 |
| 101 test('detached', () { |
| 102 a.remove(); |
| 103 customElementsTakeRecords(); |
| 104 expect(invocations, ['detached']); |
| 105 }); |
| 106 |
| 107 var div = new DivElement(); |
| 108 test('nesting does not trigger attached', () { |
| 109 div.append(a); |
| 110 customElementsTakeRecords(); |
| 111 expect(invocations, []); |
| 112 }); |
| 113 |
| 114 test('nested entering triggers attached', () { |
| 115 document.body.append(div); |
| 116 customElementsTakeRecords(); |
| 117 expect(invocations, ['attached']); |
| 118 }); |
| 119 |
| 120 test('nested leaving triggers detached', () { |
| 121 div.remove(); |
| 122 customElementsTakeRecords(); |
| 123 expect(invocations, ['detached']); |
| 124 }); |
| 125 }); |
| 126 |
| 127 |
| 128 // TODO(jmesserly): remove after deprecation period. |
| 129 group('standard_events_old_callback_names', () { |
| 130 var a; |
| 131 setUp(() { |
| 132 invocations = []; |
| 133 }); |
| 134 |
| 135 test('Created', () { |
| 136 a = new Element.tag('x-a-old'); |
| 137 expect(invocations, ['created']); |
| 138 }); |
| 139 |
| 140 test('enteredView', () { |
| 141 document.body.append(a); |
| 142 customElementsTakeRecords(); |
| 143 expect(invocations, ['enteredView']); |
| 144 }); |
| 145 |
| 146 test('leftView', () { |
| 147 a.remove(); |
| 148 customElementsTakeRecords(); |
| 149 expect(invocations, ['leftView']); |
| 150 }); |
| 151 |
| 152 var div = new DivElement(); |
| 153 test('nesting does not trigger enteredView', () { |
| 154 div.append(a); |
| 155 customElementsTakeRecords(); |
| 156 expect(invocations, []); |
| 157 }); |
| 158 |
| 159 test('nested entering triggers enteredView', () { |
| 160 document.body.append(div); |
| 161 customElementsTakeRecords(); |
| 162 expect(invocations, ['enteredView']); |
| 163 }); |
| 164 |
| 165 test('nested leaving triggers leftView', () { |
| 166 div.remove(); |
| 167 customElementsTakeRecords(); |
| 168 expect(invocations, ['leftView']); |
| 169 }); |
| 170 }); |
| 171 |
| 172 |
| 173 group('viewless_document', () { |
| 174 var a; |
| 175 setUp(() { |
| 176 invocations = []; |
| 177 }); |
| 178 |
| 179 test('Created, owned by a document without a view', () { |
| 180 a = docB.createElement('x-a'); |
| 181 expect(a.ownerDocument, docB, |
| 182 reason:'new instance should be owned by the document the definition ' |
| 183 'was registered with'); |
| 184 expect(invocations, ['created'], |
| 185 reason: 'calling the constructor should invoke the created callback'); |
| 186 }); |
| 187 |
| 188 test('Entered document without a view', () { |
| 189 docB.body.append(a); |
| 190 expect(invocations, [], |
| 191 reason: 'attached callback should not be invoked when entering a ' |
| 192 'document without a view'); |
| 193 }); |
| 194 |
| 195 test('Attribute changed in document without a view', () { |
| 196 a.setAttribute('data-foo', 'bar'); |
| 197 expect(invocations, ['attribute changed'], |
| 198 reason: 'changing an attribute should invoke the callback, even in a ' |
| 199 'document without a view'); |
| 200 }); |
| 201 |
| 202 test('Entered document with a view', () { |
| 203 document.body.append(a); |
| 204 customElementsTakeRecords(); |
| 205 expect(invocations, ['attached'], |
| 206 reason: 'attached callback should be invoked when entering a document
' |
| 207 'with a view'); |
| 208 }); |
| 209 |
| 210 test('Left document with a view', () { |
| 211 a.remove(); |
| 212 customElementsTakeRecords(); |
| 213 expect(invocations, ['detached'], |
| 214 reason: 'detached callback should be invoked when leaving a document ' |
| 215 'with a view'); |
| 216 }); |
| 217 |
| 218 test('Created in a document without a view', () { |
| 219 docB.body.setInnerHtml('<x-a></x-a>', treeSanitizer: nullSanitizer); |
| 220 upgradeCustomElements(docB.body); |
| 221 |
| 222 expect(invocations, ['created'], |
| 223 reason: 'only created callback should be invoked when parsing a ' |
| 224 'custom element in a document without a view'); |
| 225 }); |
| 226 }); |
| 227 |
| 228 group('shadow_dom', () { |
| 229 var div; |
| 230 var s; |
| 231 setUp(() { |
| 232 invocations = []; |
| 233 div = new DivElement(); |
| 234 s = div.createShadowRoot(); |
| 235 }); |
| 236 |
| 237 tearDown(() { |
| 238 customElementsTakeRecords(); |
| 239 }); |
| 240 |
| 241 test('Created in Shadow DOM that is not in a document', () { |
| 242 s.setInnerHtml('<x-a></x-a>', treeSanitizer: nullSanitizer); |
| 243 upgradeCustomElements(s); |
| 244 |
| 245 expect(invocations, ['created'], |
| 246 reason: 'the attached callback should not be invoked when entering a ' |
| 247 'Shadow DOM subtree not in the document'); |
| 248 }); |
| 249 |
| 250 test('Leaves Shadow DOM that is not in a document', () { |
| 251 s.innerHtml = ''; |
| 252 expect(invocations, [], |
| 253 reason: 'the detached callback should not be invoked when leaving a ' |
| 254 'Shadow DOM subtree not in the document'); |
| 255 }); |
| 256 |
| 257 test('Enters a document with a view as a constituent of Shadow DOM', () { |
| 258 s.setInnerHtml('<x-a></x-a>', treeSanitizer: nullSanitizer); |
| 259 upgradeCustomElements(s); |
| 260 |
| 261 document.body.append(div); |
| 262 customElementsTakeRecords(); |
| 263 expect(invocations, ['created', 'attached'], |
| 264 reason: 'the attached callback should be invoked when inserted into
' |
| 265 'a document with a view as part of Shadow DOM'); |
| 266 |
| 267 div.remove(); |
| 268 customElementsTakeRecords(); |
| 269 |
| 270 expect(invocations, ['created', 'attached', 'detached'], |
| 271 reason: 'the detached callback should be invoked when removed from a ' |
| 272 'document with a view as part of Shadow DOM'); |
| 273 }); |
| 274 }); |
| 275 |
| 276 |
| 277 group('disconnected_subtree', () { |
| 278 var div = new DivElement(); |
| 279 |
| 280 setUp(() { |
| 281 invocations = []; |
| 282 }); |
| 283 |
| 284 test('Enters a disconnected subtree of DOM', () { |
| 285 div.setInnerHtml('<x-a></x-a>', treeSanitizer: nullSanitizer); |
| 286 upgradeCustomElements(div); |
| 287 |
| 288 expect(invocations, ['created'], |
| 289 reason: 'the attached callback should not be invoked when inserted ' |
| 290 'into a disconnected subtree'); |
| 291 }); |
| 292 |
| 293 test('Leaves a disconnected subtree of DOM', () { |
| 294 div.innerHtml = ''; |
| 295 expect(invocations, [], |
| 296 reason: 'the detached callback should not be invoked when removed from
a ' |
| 297 'disconnected subtree'); |
| 298 }); |
| 299 |
| 300 test('Enters a document with a view as a constituent of a subtree', () { |
| 301 div.setInnerHtml('<x-a></x-a>', treeSanitizer: nullSanitizer); |
| 302 upgradeCustomElements(div); |
| 303 invocations = []; |
| 304 document.body.append(div); |
| 305 customElementsTakeRecords(); |
| 306 expect(invocations, ['attached'], |
| 307 reason: 'the attached callback should be invoked when inserted into a
' |
| 308 'document with a view as part of a subtree'); |
| 309 }); |
| 310 }); |
| 311 } |
OLD | NEW |