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 template_binding.test.binding_syntax; |
| 6 |
| 7 import 'dart:collection'; |
| 8 import 'dart:html'; |
| 9 import 'package:template_binding/template_binding.dart'; |
| 10 import 'package:observe/observe.dart'; |
| 11 import 'package:unittest/html_config.dart'; |
| 12 import 'package:unittest/unittest.dart'; |
| 13 import 'utils.dart'; |
| 14 |
| 15 // Note: this test is executed by template_element_test.dart |
| 16 |
| 17 syntaxTests(FooBarModel fooModel([foo, bar])) { |
| 18 observeTest('prepareBinding', () { |
| 19 var model = fooModel('bar'); |
| 20 var testSyntax = new TestBindingSyntax(); |
| 21 var div = createTestHtml( |
| 22 '<template bind>{{ foo }}' |
| 23 '<template bind>{{ foo }}</template>' |
| 24 '</template>'); |
| 25 recursivelySetTemplateModel(div, model, testSyntax); |
| 26 performMicrotaskCheckpoint(); |
| 27 expect(div.nodes.length, 4); |
| 28 expect(div.nodes.last.text, 'bar'); |
| 29 expect(div.nodes[2].tagName, 'TEMPLATE'); |
| 30 expect(testSyntax.log, [ |
| 31 ['prepare', '', 'bind', 'TEMPLATE'], |
| 32 ['bindFn', model, 'TEMPLATE', 0], |
| 33 ['prepare', 'foo', 'text', 'TEXT'], |
| 34 ['prepare', '', 'bind', 'TEMPLATE'], |
| 35 ['bindFn', model, 'TEXT', 2], |
| 36 ['bindFn', model, 'TEMPLATE', 3], |
| 37 ['prepare', 'foo', 'text', 'TEXT'], |
| 38 ['bindFn', model, 'TEXT', 6], |
| 39 ]); |
| 40 }); |
| 41 |
| 42 observeTest('prepareInstanceModel', () { |
| 43 var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]); |
| 44 |
| 45 var testSyntax = new TestModelSyntax(); |
| 46 testSyntax.altModels.addAll([fooModel('a'), fooModel('b'), fooModel('c')]); |
| 47 |
| 48 var div = createTestHtml('<template repeat>{{ foo }}</template>'); |
| 49 |
| 50 var template = div.nodes[0]; |
| 51 recursivelySetTemplateModel(div, model, testSyntax); |
| 52 performMicrotaskCheckpoint(); |
| 53 |
| 54 expect(div.nodes.length, 4); |
| 55 expect(div.nodes[0].tagName, 'TEMPLATE'); |
| 56 expect(div.nodes[1].text, 'a'); |
| 57 expect(div.nodes[2].text, 'b'); |
| 58 expect(div.nodes[3].text, 'c'); |
| 59 |
| 60 expect(testSyntax.log, [ |
| 61 ['prepare', template], |
| 62 ['bindFn', model[0]], |
| 63 ['bindFn', model[1]], |
| 64 ['bindFn', model[2]], |
| 65 ]); |
| 66 }); |
| 67 |
| 68 observeTest('prepareInstanceModel - reorder instances', () { |
| 69 var model = toObservable([0, 1, 2]); |
| 70 |
| 71 var div = createTestHtml('<template repeat>{{}}</template>'); |
| 72 var template = div.firstChild; |
| 73 var delegate = new TestInstanceModelSyntax(); |
| 74 |
| 75 recursivelySetTemplateModel(div, model, delegate); |
| 76 performMicrotaskCheckpoint(); |
| 77 expect(delegate.prepareCount, 1); |
| 78 expect(delegate.callCount, 3); |
| 79 |
| 80 // Note: intentionally mutate in place. |
| 81 model.replaceRange(0, model.length, model.reversed.toList()); |
| 82 performMicrotaskCheckpoint(); |
| 83 expect(delegate.prepareCount, 1); |
| 84 expect(delegate.callCount, 3); |
| 85 }); |
| 86 |
| 87 observeTest('prepareInstancePositionChanged', () { |
| 88 var model = toObservable(['a', 'b', 'c']); |
| 89 |
| 90 var div = createTestHtml('<template repeat>{{}}</template>'); |
| 91 var delegate = new TestPositionChangedSyntax(); |
| 92 |
| 93 var template = div.nodes[0]; |
| 94 recursivelySetTemplateModel(div, model, delegate); |
| 95 performMicrotaskCheckpoint(); |
| 96 |
| 97 expect(div.nodes.length, 4); |
| 98 expect(div.nodes[0].tagName, 'TEMPLATE'); |
| 99 expect(div.nodes[1].text, 'a'); |
| 100 expect(div.nodes[2].text, 'b'); |
| 101 expect(div.nodes[3].text, 'c'); |
| 102 |
| 103 expect(delegate.log, [ |
| 104 ['prepare', template], |
| 105 ['bindFn', model[0], 0], |
| 106 ['bindFn', model[1], 1], |
| 107 ['bindFn', model[2], 2], |
| 108 ]); |
| 109 |
| 110 delegate.log.clear(); |
| 111 |
| 112 model.removeAt(1); |
| 113 performMicrotaskCheckpoint(); |
| 114 |
| 115 expect(delegate.log, [['bindFn', 'c', 1]], reason: 'removed item'); |
| 116 |
| 117 expect(div.nodes.skip(1).map((n) => n.text), ['a', 'c']); |
| 118 }); |
| 119 |
| 120 observeTest('Basic', () { |
| 121 var model = fooModel(2, 4); |
| 122 var div = createTestHtml( |
| 123 '<template bind>' |
| 124 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); |
| 125 recursivelySetTemplateModel(div, model, new TimesTwoSyntax()); |
| 126 performMicrotaskCheckpoint(); |
| 127 expect(div.nodes.length, 2); |
| 128 expect(div.nodes.last.text, '2 + 8 + '); |
| 129 |
| 130 model.foo = 4; |
| 131 model.bar = 8; |
| 132 performMicrotaskCheckpoint(); |
| 133 expect(div.nodes.last.text, '4 + 16 + '); |
| 134 }); |
| 135 |
| 136 // Note: issue-141 test not included here as it's not related to the |
| 137 // BindingDelegate |
| 138 } |
| 139 |
| 140 // TODO(jmesserly): mocks would be cleaner here. |
| 141 |
| 142 class TestBindingSyntax extends BindingDelegate { |
| 143 var log = []; |
| 144 |
| 145 prepareBinding(String path, String name, Node node) { |
| 146 var tagName = node is Element ? node.tagName : 'TEXT'; |
| 147 int id = log.length; |
| 148 log.add(['prepare', path, name, tagName]); |
| 149 final outerNode = node; |
| 150 return (model, node) { |
| 151 var tagName = node is Element ? node.tagName : 'TEXT'; |
| 152 log.add(['bindFn', model, tagName, id]); |
| 153 }; |
| 154 } |
| 155 } |
| 156 |
| 157 class TestModelSyntax extends BindingDelegate { |
| 158 var log = []; |
| 159 var altModels = new ListQueue(); |
| 160 |
| 161 prepareInstanceModel(template) { |
| 162 log.add(['prepare', template]); |
| 163 return (model) { |
| 164 log.add(['bindFn', model]); |
| 165 return altModels.removeFirst(); |
| 166 }; |
| 167 } |
| 168 } |
| 169 |
| 170 class TestInstanceModelSyntax extends BindingDelegate { |
| 171 int prepareCount = 0; |
| 172 int callCount = 0; |
| 173 prepareInstanceModel(template) { |
| 174 prepareCount++; |
| 175 return (model) { |
| 176 callCount++; |
| 177 return model; |
| 178 }; |
| 179 } |
| 180 } |
| 181 |
| 182 |
| 183 class TestPositionChangedSyntax extends BindingDelegate { |
| 184 var log = []; |
| 185 |
| 186 prepareInstancePositionChanged(template) { |
| 187 int id = log.length; |
| 188 log.add(['prepare', template]); |
| 189 return (templateInstance, index) { |
| 190 log.add(['bindFn', templateInstance.model, index]); |
| 191 }; |
| 192 } |
| 193 } |
| 194 |
| 195 |
| 196 class TimesTwoSyntax extends BindingDelegate { |
| 197 prepareBinding(path, name, node) { |
| 198 path = path.trim(); |
| 199 if (!path.startsWith('2x:')) return null; |
| 200 |
| 201 path = path.substring(3); |
| 202 return (model, _) { |
| 203 return new PathObserver(model, path, computeValue: (x) => 2 * x); |
| 204 }; |
| 205 } |
| 206 } |
OLD | NEW |