| 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_test; | |
| 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 file ported from | |
| 16 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js | |
| 17 | |
| 18 main() { | |
| 19 useHtmlConfiguration(); | |
| 20 | |
| 21 group('Syntax FooBarModel', () { | |
| 22 syntaxTests(([f, b]) => new FooBarModel(f, b)); | |
| 23 }); | |
| 24 group('Syntax FooBarNotifyModel', () { | |
| 25 syntaxTests(([f, b]) => new FooBarNotifyModel(f, b)); | |
| 26 }); | |
| 27 } | |
| 28 | |
| 29 syntaxTests(FooBarModel fooModel([foo, bar])) { | |
| 30 setUp(() { | |
| 31 document.body.append(testDiv = new DivElement()); | |
| 32 }); | |
| 33 | |
| 34 tearDown(() { | |
| 35 testDiv.remove(); | |
| 36 testDiv = null; | |
| 37 }); | |
| 38 | |
| 39 observeTest('Registration', () { | |
| 40 var model = fooModel('bar'); | |
| 41 var testSyntax = new TestBindingSyntax(); | |
| 42 var div = createTestHtml('<template bind>{{ foo }}' | |
| 43 '<template bind>{{ foo }}</template></template>'); | |
| 44 recursivelySetTemplateModel(div, model, testSyntax); | |
| 45 performMicrotaskCheckpoint(); | |
| 46 expect(div.nodes.length, 4); | |
| 47 expect(div.nodes.last.text, 'bar'); | |
| 48 expect(div.nodes[2].tagName, 'TEMPLATE'); | |
| 49 expect(testSyntax.log, [ | |
| 50 [model, '', 'bind', 'TEMPLATE'], | |
| 51 [model, 'foo', 'text', null], | |
| 52 [model, '', 'bind', 'TEMPLATE'], | |
| 53 [model, 'foo', 'text', null], | |
| 54 ]); | |
| 55 }); | |
| 56 | |
| 57 observeTest('getInstanceModel', () { | |
| 58 var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]); | |
| 59 | |
| 60 var testSyntax = new TestModelSyntax(); | |
| 61 testSyntax.altModels.addAll([fooModel('a'), fooModel('b'), fooModel('c')]); | |
| 62 | |
| 63 var div = createTestHtml('<template repeat>{{ foo }}</template>'); | |
| 64 | |
| 65 var template = div.nodes[0]; | |
| 66 recursivelySetTemplateModel(div, model, testSyntax); | |
| 67 performMicrotaskCheckpoint(); | |
| 68 | |
| 69 expect(div.nodes.length, 4); | |
| 70 expect(div.nodes[0].tagName, 'TEMPLATE'); | |
| 71 expect(div.nodes[1].text, 'a'); | |
| 72 expect(div.nodes[2].text, 'b'); | |
| 73 expect(div.nodes[3].text, 'c'); | |
| 74 | |
| 75 expect(testSyntax.log, [ | |
| 76 [template, model[0]], | |
| 77 [template, model[1]], | |
| 78 [template, model[2]], | |
| 79 ]); | |
| 80 }); | |
| 81 | |
| 82 observeTest('getInstanceModel - reorder instances', () { | |
| 83 var model = toObservable([0, 1, 2]); | |
| 84 | |
| 85 var div = createTestHtml('<template repeat syntax="Test">{{}}</template>'); | |
| 86 var template = div.firstChild; | |
| 87 var delegate = new TestInstanceModelSyntax(); | |
| 88 | |
| 89 recursivelySetTemplateModel(div, model, delegate); | |
| 90 performMicrotaskCheckpoint(); | |
| 91 expect(delegate.count, 3); | |
| 92 | |
| 93 // Note: intentionally mutate in place. | |
| 94 model.replaceRange(0, model.length, model.reversed.toList()); | |
| 95 performMicrotaskCheckpoint(); | |
| 96 expect(delegate.count, 3); | |
| 97 }); | |
| 98 | |
| 99 observeTest('Basic', () { | |
| 100 var model = fooModel(2, 4); | |
| 101 var div = createTestHtml( | |
| 102 '<template bind syntax="2x">' | |
| 103 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); | |
| 104 recursivelySetTemplateModel(div, model, new TimesTwoSyntax()); | |
| 105 performMicrotaskCheckpoint(); | |
| 106 expect(div.nodes.length, 2); | |
| 107 expect(div.nodes.last.text, '2 + 8 + '); | |
| 108 | |
| 109 model.foo = 4; | |
| 110 model.bar = 8; | |
| 111 performMicrotaskCheckpoint(); | |
| 112 expect(div.nodes.last.text, '4 + 16 + '); | |
| 113 }); | |
| 114 } | |
| 115 | |
| 116 // TODO(jmesserly): mocks would be cleaner here. | |
| 117 | |
| 118 class TestBindingSyntax extends BindingDelegate { | |
| 119 var log = []; | |
| 120 | |
| 121 getBinding(model, String path, String name, node) { | |
| 122 log.add([model, path, name, node is Element ? node.tagName : null]); | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 class TestModelSyntax extends BindingDelegate { | |
| 127 var log = []; | |
| 128 var altModels = new ListQueue(); | |
| 129 | |
| 130 getInstanceModel(template, model) { | |
| 131 log.add([template, model]); | |
| 132 return altModels.removeFirst(); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 class TestInstanceModelSyntax extends BindingDelegate { | |
| 137 int count = 0; | |
| 138 getInstanceModel(template, model) { | |
| 139 count++; | |
| 140 return model; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 // Note: this isn't a very smart whitespace handler. A smarter one would only | |
| 145 // trim indentation, not all whitespace. | |
| 146 // See "trimOrCompact" in the web_ui Pub package. | |
| 147 class WhitespaceRemover extends BindingDelegate { | |
| 148 int trimmed = 0; | |
| 149 int removed = 0; | |
| 150 | |
| 151 DocumentFragment getInstanceFragment(Element template) { | |
| 152 var instance = templateBind(template).createInstance(); | |
| 153 var walker = new TreeWalker(instance, NodeFilter.SHOW_TEXT); | |
| 154 | |
| 155 var toRemove = []; | |
| 156 while (walker.nextNode() != null) { | |
| 157 var node = walker.currentNode; | |
| 158 var text = node.text.replaceAll('\n', '').trim(); | |
| 159 if (text.length != node.text.length) { | |
| 160 if (text.length == 0) { | |
| 161 toRemove.add(node); | |
| 162 } else { | |
| 163 trimmed++; | |
| 164 node.text = text; | |
| 165 } | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 for (var node in toRemove) node.remove(); | |
| 170 removed += toRemove.length; | |
| 171 | |
| 172 return instance; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 class TimesTwoSyntax extends BindingDelegate { | |
| 177 getBinding(model, path, name, node) { | |
| 178 path = path.trim(); | |
| 179 if (!path.startsWith('2x:')) return null; | |
| 180 | |
| 181 path = path.substring(3); | |
| 182 return new CompoundBinding((values) => values['value'] * 2) | |
| 183 ..bind('value', model, path); | |
| 184 } | |
| 185 } | |
| OLD | NEW |