| 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 binding_syntax_test; | 5 library binding_syntax_test; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:html'; | 9 import 'dart:html'; |
| 10 import 'package:mdv/mdv.dart' as mdv; | 10 import 'package:mdv/mdv.dart' as mdv; |
| 11 import 'package:observe/observe.dart'; | 11 import 'package:observe/observe.dart'; |
| 12 import 'package:unittest/html_config.dart'; | 12 import 'package:unittest/html_config.dart'; |
| 13 import 'package:unittest/unittest.dart'; | 13 import 'package:unittest/unittest.dart'; |
| 14 import 'observe_utils.dart'; | 14 import 'mdv_test_utils.dart'; |
| 15 | 15 |
| 16 // Note: this file ported from | 16 // Note: this file ported from |
| 17 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js | 17 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js |
| 18 | 18 |
| 19 main() { | 19 main() { |
| 20 mdv.initialize(); | 20 mdv.initialize(); |
| 21 useHtmlConfiguration(); | 21 useHtmlConfiguration(); |
| 22 group('Syntax', syntaxTests); | 22 |
| 23 group('Syntax FooBarModel', () { |
| 24 syntaxTests(([f, b]) => new FooBarModel(f, b)); |
| 25 }); |
| 26 group('Syntax FooBarNotifyModel', () { |
| 27 syntaxTests(([f, b]) => new FooBarNotifyModel(f, b)); |
| 28 }); |
| 23 } | 29 } |
| 24 | 30 |
| 25 syntaxTests() { | 31 syntaxTests(FooBarModel fooModel([foo, bar])) { |
| 26 var testDiv; | 32 var testDiv; |
| 27 | 33 |
| 28 setUp(() { | 34 setUp(() { |
| 29 document.body.append(testDiv = new DivElement()); | 35 document.body.append(testDiv = new DivElement()); |
| 30 }); | 36 }); |
| 31 | 37 |
| 32 tearDown(() { | 38 tearDown(() { |
| 33 testDiv.remove(); | 39 testDiv.remove(); |
| 34 testDiv = null; | 40 testDiv = null; |
| 35 }); | 41 }); |
| 36 | 42 |
| 37 createTestHtml(s) { | 43 createTestHtml(s) { |
| 38 var div = new DivElement(); | 44 var div = new DivElement(); |
| 39 div.innerHtml = s; | 45 div.innerHtml = s; |
| 40 testDiv.append(div); | 46 testDiv.append(div); |
| 41 | 47 |
| 42 for (var node in div.queryAll('*')) { | 48 for (var node in div.queryAll('*')) { |
| 43 if (node.isTemplate) TemplateElement.decorate(node); | 49 if (node.isTemplate) TemplateElement.decorate(node); |
| 44 } | 50 } |
| 45 | 51 |
| 46 return div; | 52 return div; |
| 47 } | 53 } |
| 48 | 54 |
| 49 recursivelySetTemplateModel(element, model) { | 55 recursivelySetTemplateModel(element, model) { |
| 50 for (var node in element.queryAll('*')) { | 56 for (var node in element.queryAll('*')) { |
| 51 if (node.isTemplate) node.model = model; | 57 if (node.isTemplate) node.model = model; |
| 52 } | 58 } |
| 53 } | 59 } |
| 54 | 60 |
| 55 test('Registration', () { | 61 observeTest('Registration', () { |
| 56 var model = toSymbolMap({'foo': 'bar'}); | 62 var model = fooModel('bar'); |
| 57 | 63 |
| 58 var testSyntax = new TestBindingSyntax(); | 64 var testSyntax = new TestBindingSyntax(); |
| 59 TemplateElement.syntax['Test'] = testSyntax; | 65 TemplateElement.syntax['Test'] = testSyntax; |
| 60 try { | 66 try { |
| 61 var div = createTestHtml( | 67 var div = createTestHtml( |
| 62 '<template bind syntax="Test">{{ foo }}' + | 68 '<template bind syntax="Test">{{ foo }}' + |
| 63 '<template bind>{{ foo }}</template></template>'); | 69 '<template bind>{{ foo }}</template></template>'); |
| 64 recursivelySetTemplateModel(div, model); | 70 recursivelySetTemplateModel(div, model); |
| 65 deliverChangeRecords(); | 71 performMicrotaskCheckpoint(); |
| 66 expect(div.nodes.length, 4); | 72 expect(div.nodes.length, 4); |
| 67 expect(div.nodes.last.text, 'bar'); | 73 expect(div.nodes.last.text, 'bar'); |
| 68 expect(div.nodes[2].tagName, 'TEMPLATE'); | 74 expect(div.nodes[2].tagName, 'TEMPLATE'); |
| 69 expect(div.nodes[2].attributes['syntax'], 'Test'); | 75 expect(div.nodes[2].attributes['syntax'], 'Test'); |
| 70 | 76 |
| 71 expect(testSyntax.log, [ | 77 expect(testSyntax.log, [ |
| 72 [model, '', 'bind', 'TEMPLATE'], | 78 [model, '', 'bind', 'TEMPLATE'], |
| 73 [model, 'foo', 'text', null], | 79 [model, 'foo', 'text', null], |
| 74 [model, '', 'bind', 'TEMPLATE'], | 80 [model, '', 'bind', 'TEMPLATE'], |
| 75 [model, 'foo', 'text', null], | 81 [model, 'foo', 'text', null], |
| 76 ]); | 82 ]); |
| 77 } finally { | 83 } finally { |
| 78 TemplateElement.syntax.remove('Test'); | 84 TemplateElement.syntax.remove('Test'); |
| 79 } | 85 } |
| 80 }); | 86 }); |
| 81 | 87 |
| 82 test('getInstanceModel', () { | 88 observeTest('getInstanceModel', () { |
| 83 var model = toObservable([{'foo': 1}, {'foo': 2}, {'foo': 3}] | 89 var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]); |
| 84 .map(toSymbolMap)); | |
| 85 | 90 |
| 86 var testSyntax = new TestModelSyntax(); | 91 var testSyntax = new TestModelSyntax(); |
| 87 testSyntax.altModels.addAll([{'foo': 'a'}, {'foo': 'b'}, {'foo': 'c'}] | 92 testSyntax.altModels.addAll([fooModel('a'), fooModel('b'), fooModel('c')]); |
| 88 .map(toSymbolMap)); | |
| 89 | 93 |
| 90 TemplateElement.syntax['Test'] = testSyntax; | 94 TemplateElement.syntax['Test'] = testSyntax; |
| 91 try { | 95 try { |
| 92 | 96 |
| 93 var div = createTestHtml( | 97 var div = createTestHtml( |
| 94 '<template repeat syntax="Test">' + | 98 '<template repeat syntax="Test">' + |
| 95 '{{ foo }}</template>'); | 99 '{{ foo }}</template>'); |
| 96 | 100 |
| 97 var template = div.nodes[0]; | 101 var template = div.nodes[0]; |
| 98 recursivelySetTemplateModel(div, model); | 102 recursivelySetTemplateModel(div, model); |
| 99 deliverChangeRecords(); | 103 performMicrotaskCheckpoint(); |
| 100 | 104 |
| 101 expect(div.nodes.length, 4); | 105 expect(div.nodes.length, 4); |
| 102 expect(div.nodes[0].tagName, 'TEMPLATE'); | 106 expect(div.nodes[0].tagName, 'TEMPLATE'); |
| 103 expect(div.nodes[1].text, 'a'); | 107 expect(div.nodes[1].text, 'a'); |
| 104 expect(div.nodes[2].text, 'b'); | 108 expect(div.nodes[2].text, 'b'); |
| 105 expect(div.nodes[3].text, 'c'); | 109 expect(div.nodes[3].text, 'c'); |
| 106 | 110 |
| 107 expect(testSyntax.log, [ | 111 expect(testSyntax.log, [ |
| 108 [template, model[0]], | 112 [template, model[0]], |
| 109 [template, model[1]], | 113 [template, model[1]], |
| 110 [template, model[2]], | 114 [template, model[2]], |
| 111 ]); | 115 ]); |
| 112 | 116 |
| 113 } finally { | 117 } finally { |
| 114 TemplateElement.syntax.remove('Test'); | 118 TemplateElement.syntax.remove('Test'); |
| 115 } | 119 } |
| 116 }); | 120 }); |
| 117 | 121 |
| 118 test('Basic', () { | 122 observeTest('Basic', () { |
| 119 var model = toSymbolMap({'foo': 2, 'bar': 4}); | 123 var model = fooModel(2, 4); |
| 120 | 124 |
| 121 TemplateElement.syntax['2x'] = new TimesTwoSyntax(); | 125 TemplateElement.syntax['2x'] = new TimesTwoSyntax(); |
| 122 | 126 |
| 123 var div = createTestHtml( | 127 var div = createTestHtml( |
| 124 '<template bind syntax="2x">' | 128 '<template bind syntax="2x">' |
| 125 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); | 129 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); |
| 126 recursivelySetTemplateModel(div, model); | 130 recursivelySetTemplateModel(div, model); |
| 127 deliverChangeRecords(); | 131 performMicrotaskCheckpoint(); |
| 128 expect(div.nodes.length, 2); | 132 expect(div.nodes.length, 2); |
| 129 expect(div.nodes.last.text, '2 + 8 + '); | 133 expect(div.nodes.last.text, '2 + 8 + '); |
| 130 | 134 |
| 131 model[const Symbol('foo')] = 4; | 135 model.foo = 4; |
| 132 model[const Symbol('bar')] = 8; | 136 model.bar = 8; |
| 133 deliverChangeRecords(); | 137 performMicrotaskCheckpoint(); |
| 134 expect(div.nodes.last.text, '4 + 16 + '); | 138 expect(div.nodes.last.text, '4 + 16 + '); |
| 135 | 139 |
| 136 TemplateElement.syntax.remove('2x'); | 140 TemplateElement.syntax.remove('2x'); |
| 137 }); | 141 }); |
| 138 | 142 |
| 139 test('Different Sub-Template Syntax', () { | 143 observeTest('Different Sub-Template Syntax', () { |
| 140 var model = toSymbolMap({'foo': 'bar'}); | 144 var model = fooModel('bar'); |
| 141 | 145 |
| 142 TemplateElement.syntax['Test'] = new TestBindingSyntax(); | 146 TemplateElement.syntax['Test'] = new TestBindingSyntax(); |
| 143 TemplateElement.syntax['Test2'] = new TestBindingSyntax(); | 147 TemplateElement.syntax['Test2'] = new TestBindingSyntax(); |
| 144 | 148 |
| 145 var div = createTestHtml( | 149 var div = createTestHtml( |
| 146 '<template bind syntax="Test">{{ foo }}' | 150 '<template bind syntax="Test">{{ foo }}' |
| 147 '<template bind syntax="Test2">{{ foo }}</template></template>'); | 151 '<template bind syntax="Test2">{{ foo }}</template></template>'); |
| 148 recursivelySetTemplateModel(div, model); | 152 recursivelySetTemplateModel(div, model); |
| 149 deliverChangeRecords(); | 153 performMicrotaskCheckpoint(); |
| 150 expect(div.nodes.length, 4); | 154 expect(div.nodes.length, 4); |
| 151 expect(div.nodes.last.text, 'bar'); | 155 expect(div.nodes.last.text, 'bar'); |
| 152 expect(div.nodes[2].tagName, 'TEMPLATE'); | 156 expect(div.nodes[2].tagName, 'TEMPLATE'); |
| 153 expect(div.nodes[2].attributes['syntax'], 'Test2'); | 157 expect(div.nodes[2].attributes['syntax'], 'Test2'); |
| 154 | 158 |
| 155 var testLog = TemplateElement.syntax['Test'].log; | 159 var testLog = TemplateElement.syntax['Test'].log; |
| 156 var test2Log = TemplateElement.syntax['Test2'].log; | 160 var test2Log = TemplateElement.syntax['Test2'].log; |
| 157 | 161 |
| 158 expect(testLog, [ | 162 expect(testLog, [ |
| 159 [model, '', 'bind', 'TEMPLATE'], | 163 [model, '', 'bind', 'TEMPLATE'], |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 } | 217 } |
| 214 } | 218 } |
| 215 | 219 |
| 216 for (var node in toRemove) node.remove(); | 220 for (var node in toRemove) node.remove(); |
| 217 removed += toRemove.length; | 221 removed += toRemove.length; |
| 218 | 222 |
| 219 return instance; | 223 return instance; |
| 220 } | 224 } |
| 221 } | 225 } |
| 222 | 226 |
| 223 | |
| 224 class TimesTwoSyntax extends CustomBindingSyntax { | 227 class TimesTwoSyntax extends CustomBindingSyntax { |
| 225 getBinding(model, path, name, node) { | 228 getBinding(model, path, name, node) { |
| 226 path = path.trim(); | 229 path = path.trim(); |
| 227 if (!path.startsWith('2x:')) return null; | 230 if (!path.startsWith('2x:')) return null; |
| 228 | 231 |
| 229 path = path.substring(3); | 232 path = path.substring(3); |
| 230 return new CompoundBinding((values) => values['value'] * 2) | 233 return new CompoundBinding((values) => values['value'] * 2) |
| 231 ..bind('value', model, path); | 234 ..bind('value', model, path); |
| 232 } | 235 } |
| 233 } | 236 } |
| OLD | NEW |