OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 @TestOn('browser') | 4 @TestOn('browser') |
5 library polymer_elements.test.firebase_collection_test; | 5 library polymer_elements.test.firebase_collection_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:js'; | 8 import 'dart:js'; |
9 import 'package:polymer/polymer.dart'; | 9 import 'package:polymer/polymer.dart'; |
10 import 'package:polymer_elements/firebase_collection.dart'; | 10 import 'package:polymer_elements/firebase_collection.dart'; |
11 import 'package:web_components/web_components.dart'; | 11 import 'package:web_components/web_components.dart'; |
12 import 'package:test/test.dart'; | 12 import 'package:test/test.dart'; |
13 import 'common.dart'; | 13 import 'common.dart'; |
| 14 import 'firebase_test_helpers.dart'; |
14 | 15 |
15 main() async { | 16 main() async { |
16 await initWebComponents(); | 17 await initWebComponents(); |
17 | 18 |
18 group('<firebase-collection>', () { | 19 group('firebase-collection', () { |
19 FirebaseCollection firebase; | 20 FirebaseCollection firebase; |
20 | 21 |
21 group('collection manipulation', () { | 22 tearDown(() { |
| 23 if (firebase != null) removeFirebase(firebase); |
| 24 }); |
| 25 |
| 26 group('basic usage', () { |
| 27 var numberOfItems; |
| 28 |
| 29 setUp(() { |
| 30 numberOfItems = 3; |
| 31 firebase = |
| 32 fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); |
| 33 return wait(1); |
| 34 }); |
| 35 |
| 36 test('exposes data as an array', () { |
| 37 expect(firebase.data is List, isTrue); |
| 38 expect(firebase.data.length, numberOfItems); |
| 39 }); |
| 40 |
| 41 test('receives data from Firebase location', () { |
| 42 expect(firebase.data[0]['value'] is num, isTrue); |
| 43 }); |
| 44 }); |
| 45 |
| 46 group('ordered primitives', () { |
| 47 var numberOfItems; |
| 48 |
| 49 setUp(() { |
| 50 numberOfItems = 5; |
| 51 firebase = fixtureFirebase( |
| 52 'TrivialCollection', arrayOfPrimitives(numberOfItems)); |
| 53 firebase.orderByValue = true; |
| 54 }); |
| 55 |
| 56 test('converts primitives into objects with a value key', () { |
| 57 expect(firebase.data[0] is JsObject, isTrue); |
| 58 }); |
| 59 |
| 60 test('orders primitives by value', () { |
| 61 var lastValue = -1; |
| 62 |
| 63 expect(firebase.data.length, numberOfItems); |
| 64 |
| 65 firebase.data.forEach((datum) { |
| 66 expect(datum['value'], isNot(lessThan(lastValue))); |
| 67 lastValue = datum['value']; |
| 68 }); |
| 69 }); |
| 70 }); |
| 71 |
| 72 group('removing a value locally', () { |
| 73 var numberOfItems; |
| 74 setUp(() { |
| 75 numberOfItems = 3; |
| 76 firebase = |
| 77 fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); |
| 78 }); |
| 79 |
| 80 test('works for data-bound changes', () { |
| 81 firebase.removeAt('data', 0); |
| 82 expect(firebase.data.length, numberOfItems - 1); |
| 83 }); |
| 84 |
| 85 test('can be done with `remove`', () { |
| 86 var objectToBeRemoved = firebase.data[0]; |
| 87 firebase.firebaseRemove(objectToBeRemoved); |
| 88 |
| 89 expect(firebase.data.length, numberOfItems - 1); |
| 90 expect(firebase.data.indexOf(objectToBeRemoved), -1); |
| 91 }); |
| 92 }); |
| 93 |
| 94 group('adding a value locally', () { |
| 95 setUp(() { |
| 96 firebase = fixtureFirebase('TrivialCollection'); |
| 97 }); |
| 98 |
| 99 test('works for data-bound changes', () { |
| 100 var done = new Completer(); |
| 101 var intendedValue = randomInt(); |
| 102 // Can't call `add` since it is overridden |
| 103 firebase.add('data', intendedValue); |
| 104 var index = firebase.data.length - 1; |
| 105 |
| 106 // NOTE(cdata): See polymer/polymer#2491. |
| 107 firebase.async(() { |
| 108 expect(firebase.data[index]['value'], isNotNull); |
| 109 expect(firebase.data[index]['value'], intendedValue); |
| 110 done.complete(); |
| 111 }, waitTime: 1); |
| 112 |
| 113 return done.future; |
| 114 }); |
| 115 |
| 116 test('can be done with `add`', () { |
| 117 var done = new Completer(); |
| 118 var object = randomObject(); |
| 119 var length = firebase.data.length; |
| 120 var foundObject; |
| 121 |
| 122 firebase.firebaseAdd(new JsObject.jsify(object)); |
| 123 |
| 124 // NOTE(cdata): See polymer/polymer#2491. |
| 125 firebase.async(() { |
| 126 expect(firebase.data.length, length + 1); |
| 127 |
| 128 firebase.data.forEach((datum) { |
| 129 if (datum['value'] == object['value']) { |
| 130 foundObject = datum; |
| 131 } |
| 132 }); |
| 133 |
| 134 expect(foundObject, isNotNull); |
| 135 expect(foundObject['value'], object['value']); |
| 136 done.complete(); |
| 137 }, waitTime: 1); |
| 138 |
| 139 return done.future; |
| 140 }); |
| 141 }); |
| 142 |
| 143 group('a changing child', () { |
| 144 var numberOfItems; |
| 145 var remoteFirebase; |
| 146 |
| 147 setUp(() { |
| 148 numberOfItems = 3; |
| 149 firebase = |
| 150 fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); |
| 151 remoteFirebase = new JsObject(context['Firebase'], [firebase.location]); |
| 152 }); |
| 153 |
| 154 test('updates the child key in place with the new value', () { |
| 155 var datum = firebase.data[0]; |
| 156 var newValue = 99999; |
| 157 var key = context['Polymer']['Collection'] |
| 158 .callMethod('get', [firebase.data]).callMethod('getKey', [datum]); |
| 159 |
| 160 firebase.set('data.$key.value', newValue); |
| 161 |
| 162 expect(firebase.data[0]['value'], newValue); |
| 163 }); |
| 164 }); |
| 165 |
| 166 group('syncing collections', () { |
| 167 var numberOfItems; |
| 168 var remoteFirebase; |
| 169 |
| 170 setUp(() { |
| 171 numberOfItems = 3; |
| 172 |
| 173 firebase = fixtureFirebase('TrivialCollection', arrayOfObjects(3)); |
| 174 firebase.orderValueType = 'number'; |
| 175 firebase.orderByValue = true; |
| 176 |
| 177 remoteFirebase = new JsObject(context['Firebase'], [firebase.location]); |
| 178 }); |
| 179 |
| 180 test('sync a new item at the correct index', () { |
| 181 var firstValue = firebase.data[0]; |
| 182 var secondValue = firebase.data[1]; |
| 183 var datum = firebase.data[0]; |
| 184 var key = context['Polymer']['Collection'] |
| 185 .callMethod('get', [firebase.data]).callMethod('getKey', [datum]); |
| 186 var remoteValue; |
| 187 |
| 188 remoteFirebase.callMethod('on', [ |
| 189 'value', |
| 190 (snapshot) { |
| 191 remoteValue = snapshot.callMethod('val'); |
| 192 } |
| 193 ]); |
| 194 |
| 195 expect(remoteValue[0]['value'], firebase.data[0]['value']); |
| 196 }); |
| 197 }); |
| 198 |
| 199 group('data-bound collection manipulation', () { |
| 200 var numberOfItems; |
| 201 var elements; |
22 DomBind domBind; | 202 DomBind domBind; |
23 var dom; | 203 |
24 | 204 setUp(() { |
25 setUp(() { | 205 elements = fixture('BoundCollection'); |
26 dom = fixture('BoundCollection'); | 206 domBind = elements.querySelector('[is=dom-bind]'); |
27 domBind = dom.querySelector('[is=dom-bind]'); | 207 firebase = elements.querySelector('firebase-collection'); |
28 firebase = dom.querySelector('firebase-collection'); | 208 firebase.location = fixtureLocation(arrayOfObjects(3)); |
29 }); | 209 numberOfItems = 3; |
30 | 210 }); |
31 test('added values reflect 1-to-1 in the DOM', () { | 211 |
32 return firebase.on['firebase-value'].first.then((_) { | 212 test('splices reflect in Firebase data', () { |
33 var done = firebase.on['firebase-child-added'].first.then((_) { | 213 var done = new Completer(); |
34 expect(dom.querySelectorAll('div').length, firebase.data.length); | 214 domBind.removeAt('data', 0); |
35 }); | 215 domBind.add('data', randomObject()); |
36 domBind.insert('data', 0, {'value': 'blah'}); | 216 domBind.removeAt('data', 0); |
37 domBind.render(); | 217 domBind.addAll('data', arrayOfObjects(2)); |
38 return done; | 218 |
39 }); | 219 // NOTE(cdata): See polymer/polymer#2491. |
40 }); | 220 firebase.async(() { |
41 }, skip: 'https://github.com/dart-lang/polymer_elements/issues/62'); | 221 expect(firebase.data.length, domBind['data'].length); |
42 | 222 |
43 group('basic usage', () { | 223 for (int i = 0; i < firebase.data.length; i++) { |
44 setUp(() { | 224 var datum = firebase.data[i]; |
45 firebase = fixture('TrivialCollection'); | 225 expect(domBind['data'][i]['value'], datum['value']); |
46 }); | 226 } |
47 | 227 |
48 tearDown(() { | 228 done.complete(); |
49 firebase.disconnect(); | 229 }, waitTime: 1); |
50 }); | 230 |
51 | 231 done.future; |
52 test('exposes data as an array', () { | 232 }); |
53 return firebase.on['firebase-child-added'].first.then((_) { | 233 |
54 expect(firebase.data is List, isTrue); | 234 test('splices reflect in the DOM', () { |
55 }); | 235 var divs; |
56 }); | 236 var done = new Completer(); |
57 | 237 |
58 test('receives data from Firebase location', () { | 238 firebase.addAll('data', arrayOfObjects(3)); |
59 return firebase.on['data-changed'].first.then((_) { | 239 |
60 expect(firebase.data[0]['value'], true); | 240 firebase.async(() { |
61 }); | 241 divs = elements.querySelectorAll('div'); |
62 }); | 242 expect(divs.length, firebase.data.length); |
63 }); | 243 |
64 | 244 domBind.removeAt('data', 2); |
65 group('ordered primitives', () { | 245 domBind.add('data', randomObject()); |
66 setUp(() { | 246 |
67 firebase = fixture('PrimitiveCollection'); | 247 firebase.async(() { |
68 }); | 248 divs = elements.querySelectorAll('div'); |
69 | 249 expect(divs.length, firebase.data.length); |
70 tearDown(() { | 250 |
71 firebase.disconnect(); | 251 for (int i = 0; i < firebase.data.length; i++) { |
72 }); | 252 var datum = firebase.data[i]; |
73 | 253 var divValue = int.parse(divs[i].text); |
74 test('converts primitives into objects with a value key', () { | 254 expect(datum.value, divValue); |
75 return firebase.on['firebase-child-added'].first.then((_) { | 255 } |
76 expect(firebase.data[0], isNotNull); | 256 |
77 }); | 257 done.complete(); |
78 }); | 258 }, waitTime: 1); |
79 | 259 }, waitTime: 1); |
80 test('orders primitives by value', () { | 260 |
81 return firebase.on['firebase-value'].first.then((_) { | 261 return done.future; |
82 var lastValue = -1.0 / 0; | 262 }, skip: 'https://github.com/dart-lang/polymer_elements/issues/62'); |
83 expect(firebase.data.length, greaterThan(0)); | |
84 firebase.data.forEach((item) { | |
85 expect(item['value'], greaterThanOrEqualTo(lastValue)); | |
86 lastValue = item['value']; | |
87 }); | |
88 }); | |
89 }); | |
90 | |
91 group('adding a value locally', () { | |
92 setUp(() { | |
93 return firebase.on['firebase-value'].first; | |
94 }); | |
95 | |
96 test('can be done with `add`', () { | |
97 var length = firebase.data.length; | |
98 var newValue = firebase.data[firebase.data.length - 1]['value'] + 1; | |
99 var key; | |
100 | |
101 var done = firebase.on['firebase-child-added'].first.then((_) { | |
102 expect(firebase.data.length, length + 1); | |
103 expect(firebase.data[firebase.data.length - 1]['value'], newValue); | |
104 }).then((_) async { | |
105 await wait(1); | |
106 firebase.removeByKey(key); | |
107 }); | |
108 | |
109 key = firebase.add(newValue).callMethod('key'); | |
110 return done; | |
111 }); | |
112 }); | |
113 }); | |
114 | |
115 group('a child changes', () { | |
116 setUp(() { | |
117 firebase = fixture('ChangingChildren'); | |
118 return firebase.on['firebase-value'].first; | |
119 }); | |
120 | |
121 test('updates the child key in place with the new value', () { | |
122 var childrenKeys = []; | |
123 | |
124 var done = firebase.on['firebase-value'].first.then((_) async { | |
125 // Wait for childrenKeys to be populated | |
126 await new Future(() {}); | |
127 var middleValue = firebase.getByKey(childrenKeys[1]); | |
128 var changes; | |
129 | |
130 expect(middleValue['foo'], 1); | |
131 expect(middleValue['bar'], 1); | |
132 | |
133 changes = firebase.on['firebase-child-changed'].first; | |
134 | |
135 firebase.set('data.${firebase.data.indexOf(middleValue)}.bar', 2); | |
136 | |
137 return changes; | |
138 }).then((_) { | |
139 var middleValue = firebase.getByKey(childrenKeys[1]); | |
140 | |
141 expect(middleValue['foo'], 1); | |
142 expect(middleValue['bar'], 2); | |
143 }).then((_) { | |
144 childrenKeys.forEach((key) { | |
145 firebase.removeByKey(key); | |
146 }); | |
147 }); | |
148 | |
149 var index = -1; | |
150 childrenKeys = [0, 1, 2].map((value) { | |
151 index++; | |
152 return firebase | |
153 .add(new JsObject.jsify({'foo': value, 'bar': index})) | |
154 .callMethod('key'); | |
155 }).toList(); | |
156 | |
157 return done; | |
158 }); | |
159 }); | |
160 | |
161 group('syncing collections', () { | |
162 FirebaseCollection localFirebase; | |
163 FirebaseCollection remoteFirebase; | |
164 | |
165 setUp(() { | |
166 var children = fixture('SyncingCollections'); | |
167 localFirebase = children[0]; | |
168 remoteFirebase = children[1]; | |
169 return Future.wait([ | |
170 localFirebase.on['firebase-value'].first, | |
171 remoteFirebase.on['firebase-value'].first | |
172 ]); | |
173 }); | |
174 | |
175 test('syncs a new item at the correct index', () { | |
176 var data = {'foo': 100}; | |
177 var key; | |
178 | |
179 var done = remoteFirebase.on['firebase-value'].first.then((_) async { | |
180 await wait(1); | |
181 var value = remoteFirebase.getByKey(key); | |
182 var lowValue = remoteFirebase.getByKey('lowValue'); | |
183 var highValue = remoteFirebase.getByKey('highValue'); | |
184 | |
185 var index = remoteFirebase.data.indexOf(value); | |
186 var lowIndex = remoteFirebase.data.indexOf(lowValue); | |
187 var highIndex = remoteFirebase.data.indexOf(highValue); | |
188 | |
189 expect(value, isNotNull); | |
190 expect(index, lessThan(highIndex)); | |
191 expect(index, greaterThan(lowIndex)); | |
192 }).then((_) { | |
193 localFirebase.removeByKey(key); | |
194 }); | |
195 | |
196 key = localFirebase.add(new JsObject.jsify(data)).callMethod('key'); | |
197 | |
198 return done; | |
199 }); | |
200 }); | 263 }); |
201 }); | 264 }); |
202 } | 265 } |
OLD | NEW |