Chromium Code Reviews| Index: test/firebase_collection_test.dart | 
| diff --git a/test/firebase_collection_test.dart b/test/firebase_collection_test.dart | 
| index 8881ccb13ca74536811399293e3aeb5f632d84c5..dd23bc541163a29f544fe1c3e253e07ec3c190c5 100644 | 
| --- a/test/firebase_collection_test.dart | 
| +++ b/test/firebase_collection_test.dart | 
| @@ -11,192 +11,256 @@ import 'package:polymer_elements/firebase_collection.dart'; | 
| import 'package:web_components/web_components.dart'; | 
| import 'package:test/test.dart'; | 
| import 'common.dart'; | 
| +import 'firebase_test_helpers.dart'; | 
| main() async { | 
| await initWebComponents(); | 
| - group('<firebase-collection>', () { | 
| + group('firebase-collection', () { | 
| FirebaseCollection firebase; | 
| - group('collection manipulation', () { | 
| - DomBind domBind; | 
| - var dom; | 
| + tearDown(() { | 
| + if (firebase != null) removeFirebase(firebase); | 
| + }); | 
| + | 
| + group('basic usage', () { | 
| + var numberOfItems; | 
| setUp(() { | 
| - dom = fixture('BoundCollection'); | 
| - domBind = dom.querySelector('[is=dom-bind]'); | 
| - firebase = dom.querySelector('firebase-collection'); | 
| + numberOfItems = 3; | 
| + firebase = | 
| + fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); | 
| + return wait(1); | 
| }); | 
| - test('added values reflect 1-to-1 in the DOM', () { | 
| - return firebase.on['firebase-value'].first.then((_) { | 
| - var done = firebase.on['firebase-child-added'].first.then((_) { | 
| - expect(dom.querySelectorAll('div').length, firebase.data.length); | 
| - }); | 
| - domBind.insert('data', 0, {'value': 'blah'}); | 
| - domBind.render(); | 
| - return done; | 
| - }); | 
| + test('exposes data as an array', () { | 
| + expect(firebase.data is List, isTrue); | 
| + expect(firebase.data.length, numberOfItems); | 
| }); | 
| - }, skip: 'https://github.com/dart-lang/polymer_elements/issues/62'); | 
| - group('basic usage', () { | 
| - setUp(() { | 
| - firebase = fixture('TrivialCollection'); | 
| + test('receives data from Firebase location', () { | 
| + expect(firebase.data[0]['value'] is num, isTrue); | 
| }); | 
| + }); | 
| - tearDown(() { | 
| - firebase.disconnect(); | 
| + group('ordered primitives', () { | 
| + var numberOfItems; | 
| + | 
| + setUp(() { | 
| + numberOfItems = 5; | 
| + firebase = fixtureFirebase( | 
| + 'TrivialCollection', arrayOfPrimitives(numberOfItems)); | 
| + firebase.orderByValue = true; | 
| }); | 
| - test('exposes data as an array', () { | 
| - return firebase.on['firebase-child-added'].first.then((_) { | 
| - expect(firebase.data is List, isTrue); | 
| - }); | 
| + test('converts primitives into objects with a value key', () { | 
| + expect(firebase.data[0] is JsObject, isTrue); | 
| }); | 
| - test('receives data from Firebase location', () { | 
| - return firebase.on['data-changed'].first.then((_) { | 
| - expect(firebase.data[0]['value'], true); | 
| + test('orders primitives by value', () { | 
| + var lastValue = -1; | 
| + | 
| + expect(firebase.data.length, numberOfItems); | 
| + | 
| + firebase.data.forEach((datum) { | 
| + expect(datum['value'], isNot(lessThan(lastValue))); | 
| + lastValue = datum['value']; | 
| }); | 
| }); | 
| }); | 
| - group('ordered primitives', () { | 
| + group('removing a value locally', () { | 
| + var numberOfItems; | 
| setUp(() { | 
| - firebase = fixture('PrimitiveCollection'); | 
| + numberOfItems = 3; | 
| + firebase = | 
| + fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); | 
| }); | 
| - tearDown(() { | 
| - firebase.disconnect(); | 
| + test('works for data-bound changes', () { | 
| + firebase.removeAt('data', 0); | 
| + expect(firebase.data.length, numberOfItems - 1); | 
| }); | 
| - test('converts primitives into objects with a value key', () { | 
| - return firebase.on['firebase-child-added'].first.then((_) { | 
| - expect(firebase.data[0], isNotNull); | 
| - }); | 
| + test('can be done with `remove`', () { | 
| + var objectToBeRemoved = firebase.data[0]; | 
| + firebase.removeItem(objectToBeRemoved); | 
| + | 
| + expect(firebase.data.length, numberOfItems - 1); | 
| + expect(firebase.data.indexOf(objectToBeRemoved), -1); | 
| }); | 
| + }); | 
| - test('orders primitives by value', () { | 
| - return firebase.on['firebase-value'].first.then((_) { | 
| - var lastValue = -1.0 / 0; | 
| - expect(firebase.data.length, greaterThan(0)); | 
| - firebase.data.forEach((item) { | 
| - expect(item['value'], greaterThanOrEqualTo(lastValue)); | 
| - lastValue = item['value']; | 
| - }); | 
| - }); | 
| + group('adding a value locally', () { | 
| + setUp(() { | 
| + firebase = fixtureFirebase('TrivialCollection'); | 
| }); | 
| - group('adding a value locally', () { | 
| - setUp(() { | 
| - return firebase.on['firebase-value'].first; | 
| - }); | 
| + test('works for data-bound changes', () { | 
| + var done = new Completer(); | 
| + var intendedValue = randomInt(); | 
| + // Can't call `add` since it is overridden | 
| + var index = | 
| + firebase.jsElement.callMethod('push', ['data', intendedValue]) - 1; | 
| 
 
Siggi Cherem (dart-lang)
2015/10/28 22:35:16
should `push` be exposed in the Dart API? Is it pa
 
jakemac
2015/10/29 16:07:29
I guess what should really happen here is changing
 
 | 
| + | 
| + // NOTE(cdata): See polymer/polymer#2491. | 
| + firebase.async(() { | 
| + expect(firebase.data[index]['value'], isNotNull); | 
| + expect(firebase.data[index]['value'], intendedValue); | 
| + done.complete(); | 
| + }, waitTime: 1); | 
| + | 
| + return done.future; | 
| + }); | 
| + | 
| + test('can be done with `add`', () { | 
| + var done = new Completer(); | 
| + var object = randomObject(); | 
| + var length = firebase.data.length; | 
| + var foundObject; | 
| + | 
| + firebase.add(new JsObject.jsify(object)); | 
| - test('can be done with `add`', () { | 
| - var length = firebase.data.length; | 
| - var newValue = firebase.data[firebase.data.length - 1]['value'] + 1; | 
| - var key; | 
| - | 
| - var done = firebase.on['firebase-child-added'].first.then((_) { | 
| - expect(firebase.data.length, length + 1); | 
| - expect(firebase.data[firebase.data.length - 1]['value'], newValue); | 
| - }).then((_) async { | 
| - await wait(1); | 
| - firebase.removeByKey(key); | 
| + // NOTE(cdata): See polymer/polymer#2491. | 
| + firebase.async(() { | 
| + expect(firebase.data.length, length + 1); | 
| + | 
| + firebase.data.forEach((datum) { | 
| + if (datum['value'] == object['value']) { | 
| + foundObject = datum; | 
| + } | 
| }); | 
| - key = firebase.add(newValue).callMethod('key'); | 
| - return done; | 
| - }); | 
| + expect(foundObject, isNotNull); | 
| + expect(foundObject['value'], object['value']); | 
| + done.complete(); | 
| + }, waitTime: 1); | 
| + | 
| + return done.future; | 
| }); | 
| }); | 
| - group('a child changes', () { | 
| + group('a changing child', () { | 
| + var numberOfItems; | 
| + var remoteFirebase; | 
| + | 
| setUp(() { | 
| - firebase = fixture('ChangingChildren'); | 
| - return firebase.on['firebase-value'].first; | 
| + numberOfItems = 3; | 
| + firebase = | 
| + fixtureFirebase('TrivialCollection', arrayOfObjects(numberOfItems)); | 
| + remoteFirebase = new JsObject(context['Firebase'], [firebase.location]); | 
| }); | 
| test('updates the child key in place with the new value', () { | 
| - var childrenKeys = []; | 
| + var datum = firebase.data[0]; | 
| + var newValue = 99999; | 
| + var key = context['Polymer']['Collection'] | 
| + .callMethod('get', [firebase.data]).callMethod('getKey', [datum]); | 
| - var done = firebase.on['firebase-value'].first.then((_) async { | 
| - // Wait for childrenKeys to be populated | 
| - await new Future(() {}); | 
| - var middleValue = firebase.getByKey(childrenKeys[1]); | 
| - var changes; | 
| + firebase.set('data.$key.value', newValue); | 
| - expect(middleValue['foo'], 1); | 
| - expect(middleValue['bar'], 1); | 
| + expect(firebase.data[0]['value'], newValue); | 
| + }); | 
| + }); | 
| - changes = firebase.on['firebase-child-changed'].first; | 
| + group('syncing collections', () { | 
| + var numberOfItems; | 
| + var remoteFirebase; | 
| - firebase.set('data.${firebase.data.indexOf(middleValue)}.bar', 2); | 
| + setUp(() { | 
| + numberOfItems = 3; | 
| - return changes; | 
| - }).then((_) { | 
| - var middleValue = firebase.getByKey(childrenKeys[1]); | 
| + firebase = fixtureFirebase('TrivialCollection', arrayOfObjects(3)); | 
| + firebase.orderValueType = 'number'; | 
| + firebase.orderByValue = true; | 
| - expect(middleValue['foo'], 1); | 
| - expect(middleValue['bar'], 2); | 
| - }).then((_) { | 
| - childrenKeys.forEach((key) { | 
| - firebase.removeByKey(key); | 
| - }); | 
| - }); | 
| + remoteFirebase = new JsObject(context['Firebase'], [firebase.location]); | 
| + }); | 
| - var index = -1; | 
| - childrenKeys = [0, 1, 2].map((value) { | 
| - index++; | 
| - return firebase | 
| - .add(new JsObject.jsify({'foo': value, 'bar': index})) | 
| - .callMethod('key'); | 
| - }).toList(); | 
| + test('sync a new item at the correct index', () { | 
| + var firstValue = firebase.data[0]; | 
| + var secondValue = firebase.data[1]; | 
| + var datum = firebase.data[0]; | 
| + var key = context['Polymer']['Collection'] | 
| 
 
Siggi Cherem (dart-lang)
2015/10/28 22:35:16
do we want to eventually wrap these static APIs as
 
jakemac
2015/10/29 16:07:29
These collection apis are not really useful in gen
 
 | 
| + .callMethod('get', [firebase.data]).callMethod('getKey', [datum]); | 
| + var remoteValue; | 
| + | 
| + remoteFirebase.callMethod('on', [ | 
| + 'value', | 
| + (snapshot) { | 
| + remoteValue = snapshot.callMethod('val'); | 
| + } | 
| + ]); | 
| - return done; | 
| + expect(remoteValue[0]['value'], firebase.data[0]['value']); | 
| }); | 
| }); | 
| - group('syncing collections', () { | 
| - FirebaseCollection localFirebase; | 
| - FirebaseCollection remoteFirebase; | 
| + group('data-bound collection manipulation', () { | 
| + var numberOfItems; | 
| + var elements; | 
| + DomBind domBind; | 
| setUp(() { | 
| - var children = fixture('SyncingCollections'); | 
| - localFirebase = children[0]; | 
| - remoteFirebase = children[1]; | 
| - return Future.wait([ | 
| - localFirebase.on['firebase-value'].first, | 
| - remoteFirebase.on['firebase-value'].first | 
| - ]); | 
| + elements = fixture('BoundCollection'); | 
| + domBind = elements.querySelector('[is=dom-bind]'); | 
| + firebase = elements.querySelector('firebase-collection'); | 
| + firebase.location = fixtureLocation(arrayOfObjects(3)); | 
| + numberOfItems = 3; | 
| }); | 
| - test('syncs a new item at the correct index', () { | 
| - var data = {'foo': 100}; | 
| - var key; | 
| + test('splices reflect in Firebase data', () { | 
| + var done = new Completer(); | 
| + domBind.removeAt('data', 0); | 
| + domBind.add('data', randomObject()); | 
| + domBind.removeAt('data', 0); | 
| + domBind.addAll('data', arrayOfObjects(2)); | 
| - var done = remoteFirebase.on['firebase-value'].first.then((_) async { | 
| - await wait(1); | 
| - var value = remoteFirebase.getByKey(key); | 
| - var lowValue = remoteFirebase.getByKey('lowValue'); | 
| - var highValue = remoteFirebase.getByKey('highValue'); | 
| + // NOTE(cdata): See polymer/polymer#2491. | 
| + firebase.async(() { | 
| + expect(firebase.data.length, domBind['data'].length); | 
| - var index = remoteFirebase.data.indexOf(value); | 
| - var lowIndex = remoteFirebase.data.indexOf(lowValue); | 
| - var highIndex = remoteFirebase.data.indexOf(highValue); | 
| + for (int i = 0; i < firebase.data.length; i++) { | 
| + var datum = firebase.data[i]; | 
| + expect(domBind['data'][i]['value'], datum['value']); | 
| + } | 
| - expect(value, isNotNull); | 
| - expect(index, lessThan(highIndex)); | 
| - expect(index, greaterThan(lowIndex)); | 
| - }).then((_) { | 
| - localFirebase.removeByKey(key); | 
| - }); | 
| - | 
| - key = localFirebase.add(new JsObject.jsify(data)).callMethod('key'); | 
| + done.complete(); | 
| + }, waitTime: 1); | 
| - return done; | 
| + done.future; | 
| }); | 
| + | 
| + test('splices reflect in the DOM', () { | 
| + var divs; | 
| + var done = new Completer(); | 
| + | 
| + firebase.jsElement.callMethod('push', | 
| + ['data']..addAll(new JsObject.jsify(arrayOfObjects(3)) as JsArray)); | 
| + | 
| + firebase.async(() { | 
| + divs = elements.querySelectorAll('div'); | 
| + expect(divs.length, firebase.data.length); | 
| + | 
| + domBind.removeAt('data', 2); | 
| + domBind.add('data', randomObject()); | 
| + | 
| + firebase.async(() { | 
| + divs = elements.querySelectorAll('div'); | 
| + expect(divs.length, firebase.data.length); | 
| + | 
| + for (int i = 0; i < firebase.data.length; i++) { | 
| + var datum = firebase.data[i]; | 
| + var divValue = int.parse(divs[i].text); | 
| + expect(datum.value, divValue); | 
| + } | 
| + | 
| + done.complete(); | 
| + }, waitTime: 1); | 
| + }, waitTime: 1); | 
| + | 
| + return done.future; | 
| + }, skip: 'https://github.com/dart-lang/polymer_elements/issues/62'); | 
| }); | 
| }); | 
| } |