From 6f9c801e40ddb21bbb7653e2a0c09b758426ac30 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Mon, 1 Aug 2016 22:52:46 +0300 Subject: [PATCH 01/11] chore(observable): Added debounce for collection events --- modules/minimongo-observable/to-observable.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/minimongo-observable/to-observable.ts b/modules/minimongo-observable/to-observable.ts index 2ec0df9..a5e1847 100644 --- a/modules/minimongo-observable/to-observable.ts +++ b/modules/minimongo-observable/to-observable.ts @@ -1,12 +1,15 @@ import {Subscriber} from 'rxjs/Rx'; import {ObservableCursor} from './observable-cursor'; +import * as _ from 'lodash'; + +const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME : number = 100; export function toObservable(cursor : Mongo.Cursor) : ObservableCursor> { const observable = ObservableCursor.create((observer : Subscriber>) => { - const handleChange = () => { + const handleChange = _.debounce(() => { observer.next(cursor.fetch()); - }; + }, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); let handler; let isReactive = observable.isReactive(); From 1b23a51be9df867f1adc3bebf66d14a3eaf6b92c Mon Sep 17 00:00:00 2001 From: dotansimha Date: Mon, 1 Aug 2016 22:55:22 +0300 Subject: [PATCH 02/11] chore(observable): Added compiled files and fixed lint issues --- dist/minimongo-observable/to-observable.js | 6 ++++-- modules/minimongo-observable/to-observable.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dist/minimongo-observable/to-observable.js b/dist/minimongo-observable/to-observable.js index 8282abb..3514bf8 100644 --- a/dist/minimongo-observable/to-observable.js +++ b/dist/minimongo-observable/to-observable.js @@ -1,10 +1,12 @@ "use strict"; var observable_cursor_1 = require('./observable-cursor'); +var _ = require('lodash'); +var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; function toObservable(cursor) { var observable = observable_cursor_1.ObservableCursor.create(function (observer) { - var handleChange = function () { + var handleChange = _.debounce(function () { observer.next(cursor.fetch()); - }; + }, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); var handler; var isReactive = observable.isReactive(); observable._cursorRef = cursor; diff --git a/modules/minimongo-observable/to-observable.ts b/modules/minimongo-observable/to-observable.ts index a5e1847..20c5bf4 100644 --- a/modules/minimongo-observable/to-observable.ts +++ b/modules/minimongo-observable/to-observable.ts @@ -2,7 +2,7 @@ import {Subscriber} from 'rxjs/Rx'; import {ObservableCursor} from './observable-cursor'; import * as _ from 'lodash'; -const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME : number = 100; +const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; export function toObservable(cursor : Mongo.Cursor) : ObservableCursor> { const observable = From 2de0d50c22bb571059a08df8cacf611f1c640db1 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Mon, 1 Aug 2016 23:25:46 +0300 Subject: [PATCH 03/11] chore(observable): Updated usage of throttle, and added Zone.run wrapper --- dist/minimongo-observable/to-observable.js | 5 ++--- modules/minimongo-observable/to-observable.ts | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dist/minimongo-observable/to-observable.js b/dist/minimongo-observable/to-observable.js index 3514bf8..0eebfd8 100644 --- a/dist/minimongo-observable/to-observable.js +++ b/dist/minimongo-observable/to-observable.js @@ -4,9 +4,8 @@ var _ = require('lodash'); var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; function toObservable(cursor) { var observable = observable_cursor_1.ObservableCursor.create(function (observer) { - var handleChange = _.debounce(function () { - observer.next(cursor.fetch()); - }, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); + var rawHandleChange = function () { return Zone.current.run(function () { return observer.next(cursor.fetch()); }); }; + var handleChange = _.throttle(rawHandleChange, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME, { trailing: true }); var handler; var isReactive = observable.isReactive(); observable._cursorRef = cursor; diff --git a/modules/minimongo-observable/to-observable.ts b/modules/minimongo-observable/to-observable.ts index 20c5bf4..681dce0 100644 --- a/modules/minimongo-observable/to-observable.ts +++ b/modules/minimongo-observable/to-observable.ts @@ -7,9 +7,11 @@ const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; export function toObservable(cursor : Mongo.Cursor) : ObservableCursor> { const observable = ObservableCursor.create((observer : Subscriber>) => { - const handleChange = _.debounce(() => { - observer.next(cursor.fetch()); - }, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); + const rawHandleChange = () => Zone.current.run(() => observer.next(cursor.fetch())); + const handleChange = _.throttle( + rawHandleChange, + COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME, + {trailing: true}); let handler; let isReactive = observable.isReactive(); From 570e02f27dfb3fce06f44fd3cb6e8437e0f02782 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Mon, 1 Aug 2016 23:26:07 +0300 Subject: [PATCH 04/11] chore(observable): Decreased the throttle time to 16ms (60fps) --- modules/minimongo-observable/to-observable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/minimongo-observable/to-observable.ts b/modules/minimongo-observable/to-observable.ts index 681dce0..8838c24 100644 --- a/modules/minimongo-observable/to-observable.ts +++ b/modules/minimongo-observable/to-observable.ts @@ -2,7 +2,7 @@ import {Subscriber} from 'rxjs/Rx'; import {ObservableCursor} from './observable-cursor'; import * as _ from 'lodash'; -const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; +const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16; export function toObservable(cursor : Mongo.Cursor) : ObservableCursor> { const observable = From 3eaca130942872f95c761d413af8074a991e08c1 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Mon, 1 Aug 2016 23:32:14 +0300 Subject: [PATCH 05/11] chore(observable): Updated compiled file --- dist/minimongo-observable/to-observable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/minimongo-observable/to-observable.js b/dist/minimongo-observable/to-observable.js index 0eebfd8..4fb4d3f 100644 --- a/dist/minimongo-observable/to-observable.js +++ b/dist/minimongo-observable/to-observable.js @@ -1,7 +1,7 @@ "use strict"; var observable_cursor_1 = require('./observable-cursor'); var _ = require('lodash'); -var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 100; +var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16; function toObservable(cursor) { var observable = observable_cursor_1.ObservableCursor.create(function (observer) { var rawHandleChange = function () { return Zone.current.run(function () { return observer.next(cursor.fetch()); }); }; From 423dcd00fccb12827c1e8b189d56d14555f4b006 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 22:21:12 +0300 Subject: [PATCH 06/11] chore(observable): Improvements for observable performance --- dist/minimongo-observable/meteor-observable.js | 4 +++- dist/minimongo-observable/to-observable.js | 5 +++-- modules/minimongo-observable/meteor-observable.ts | 6 +++++- modules/minimongo-observable/to-observable.ts | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dist/minimongo-observable/meteor-observable.js b/dist/minimongo-observable/meteor-observable.js index 57e518c..5a6c563 100644 --- a/dist/minimongo-observable/meteor-observable.js +++ b/dist/minimongo-observable/meteor-observable.js @@ -15,7 +15,7 @@ var MeteorObservable = (function () { if (lastParam && _.isFunction(lastParam)) { throw new Error("Invalid MeteorObservable.call arguments:\n Your last param can't be a callback function, \n please remove it and use \".subscribe\" of the Observable!"); } - return rxjs_1.Observable.create(function (observer) { + var obs = rxjs_1.Observable.create(function (observer) { Meteor.call.apply(Meteor, argumentsArray.concat([ function (error, result) { if (error) { @@ -29,6 +29,8 @@ var MeteorObservable = (function () { } ])); }); + obs.publish(); + return obs; }; MeteorObservable.subscribe = function (name) { var args = []; diff --git a/dist/minimongo-observable/to-observable.js b/dist/minimongo-observable/to-observable.js index 4fb4d3f..a37def0 100644 --- a/dist/minimongo-observable/to-observable.js +++ b/dist/minimongo-observable/to-observable.js @@ -3,9 +3,10 @@ var observable_cursor_1 = require('./observable-cursor'); var _ = require('lodash'); var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16; function toObservable(cursor) { + var currentZone = Zone.current; var observable = observable_cursor_1.ObservableCursor.create(function (observer) { - var rawHandleChange = function () { return Zone.current.run(function () { return observer.next(cursor.fetch()); }); }; - var handleChange = _.throttle(rawHandleChange, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME, { trailing: true }); + var rawHandleChange = function () { return currentZone.run(function () { return observer.next(cursor.fetch()); }); }; + var handleChange = _.debounce(rawHandleChange, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); var handler; var isReactive = observable.isReactive(); observable._cursorRef = cursor; diff --git a/modules/minimongo-observable/meteor-observable.ts b/modules/minimongo-observable/meteor-observable.ts index ef47418..b7ce6db 100644 --- a/modules/minimongo-observable/meteor-observable.ts +++ b/modules/minimongo-observable/meteor-observable.ts @@ -14,7 +14,7 @@ export class MeteorObservable { please remove it and use ".subscribe" of the Observable!`); } - return Observable.create((observer: Subscriber) => { + const obs = Observable.create((observer: Subscriber) => { Meteor.call.apply(Meteor, argumentsArray.concat([ (error: Meteor.Error, result: T) => { if (error) { @@ -27,6 +27,10 @@ export class MeteorObservable { } ])); }); + + obs.publish(); + + return obs; } public static subscribe(name: string, ...args: any[]): ObservableMeteorSubscription { diff --git a/modules/minimongo-observable/to-observable.ts b/modules/minimongo-observable/to-observable.ts index 8838c24..0a60f6b 100644 --- a/modules/minimongo-observable/to-observable.ts +++ b/modules/minimongo-observable/to-observable.ts @@ -5,13 +5,13 @@ import * as _ from 'lodash'; const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16; export function toObservable(cursor : Mongo.Cursor) : ObservableCursor> { + const currentZone = Zone.current; const observable = ObservableCursor.create((observer : Subscriber>) => { - const rawHandleChange = () => Zone.current.run(() => observer.next(cursor.fetch())); - const handleChange = _.throttle( + const rawHandleChange = () => currentZone.run(() => observer.next(cursor.fetch())); + const handleChange = _.debounce( rawHandleChange, - COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME, - {trailing: true}); + COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME); let handler; let isReactive = observable.isReactive(); From df44f03f109770377ba78e7f1f9cecfcf2b224d1 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 22:48:14 +0300 Subject: [PATCH 07/11] chore(observable): Fixed for zone execution --- .../minimongo-observable/meteor-observable.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/modules/minimongo-observable/meteor-observable.ts b/modules/minimongo-observable/meteor-observable.ts index b7ce6db..bc71440 100644 --- a/modules/minimongo-observable/meteor-observable.ts +++ b/modules/minimongo-observable/meteor-observable.ts @@ -4,6 +4,7 @@ import * as _ from 'lodash'; export class MeteorObservable { public static call(name: string, ...args: any[]): Observable { + const currentZone = Zone.current; const argumentsArray: Array = Array.prototype.slice.call(arguments); const lastParam = argumentsArray[argumentsArray.length - 1]; @@ -18,11 +19,14 @@ export class MeteorObservable { Meteor.call.apply(Meteor, argumentsArray.concat([ (error: Meteor.Error, result: T) => { if (error) { - observer.error(error); - observer.complete(); + currentZone.run(() => { + observer.error(error); + observer.complete(); + }); } else { - observer.next(result); - observer.complete(); + currentZone.run(() => { + observer.next(result); + }); } } ])); @@ -34,6 +38,7 @@ export class MeteorObservable { } public static subscribe(name: string, ...args: any[]): ObservableMeteorSubscription { + const currentZone = Zone.current; const argumentsArray: Array = Array.prototype.slice.call(arguments); const lastParam = argumentsArray[argumentsArray.length - 1]; @@ -49,11 +54,13 @@ export class MeteorObservable { let handle = Meteor.subscribe.apply(Meteor, argumentsArray.concat([ { onError: (error: Meteor.Error) => { - observer.error(error); - observer.complete(); + currentZone.run(() => { + observer.error(error); + observer.complete(); + }); }, onReady: () => { - observer.next(); + currentZone.run(observer.next); } } ])); From 90cdb27a7241271ffbc29ab9a55a78128090f065 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 22:48:39 +0300 Subject: [PATCH 08/11] chore(observable): Added compiled files --- .../minimongo-observable/meteor-observable.js | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dist/minimongo-observable/meteor-observable.js b/dist/minimongo-observable/meteor-observable.js index 5a6c563..a20384a 100644 --- a/dist/minimongo-observable/meteor-observable.js +++ b/dist/minimongo-observable/meteor-observable.js @@ -10,6 +10,7 @@ var MeteorObservable = (function () { for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } + var currentZone = Zone.current; var argumentsArray = Array.prototype.slice.call(arguments); var lastParam = argumentsArray[argumentsArray.length - 1]; if (lastParam && _.isFunction(lastParam)) { @@ -19,12 +20,15 @@ var MeteorObservable = (function () { Meteor.call.apply(Meteor, argumentsArray.concat([ function (error, result) { if (error) { - observer.error(error); - observer.complete(); + currentZone.run(function () { + observer.error(error); + observer.complete(); + }); } else { - observer.next(result); - observer.complete(); + currentZone.run(function () { + observer.next(result); + }); } } ])); @@ -37,6 +41,7 @@ var MeteorObservable = (function () { for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } + var currentZone = Zone.current; var argumentsArray = Array.prototype.slice.call(arguments); var lastParam = argumentsArray[argumentsArray.length - 1]; if (lastParam && _.isObject(lastParam) && (lastParam.onReady || lastParam.onError)) { @@ -46,11 +51,13 @@ var MeteorObservable = (function () { var handle = Meteor.subscribe.apply(Meteor, argumentsArray.concat([ { onError: function (error) { - observer.error(error); - observer.complete(); + currentZone.run(function () { + observer.error(error); + observer.complete(); + }); }, onReady: function () { - observer.next(); + currentZone.run(observer.next); } } ])); From cd7f1634a19f72a949ea7f15d5234d1e3e1b5458 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 22:50:41 +0300 Subject: [PATCH 09/11] chore(observable): Fixes for Observable's next context call --- dist/minimongo-observable/meteor-observable.js | 6 ++---- modules/minimongo-observable/meteor-observable.ts | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/dist/minimongo-observable/meteor-observable.js b/dist/minimongo-observable/meteor-observable.js index a20384a..3bef5ab 100644 --- a/dist/minimongo-observable/meteor-observable.js +++ b/dist/minimongo-observable/meteor-observable.js @@ -26,9 +26,7 @@ var MeteorObservable = (function () { }); } else { - currentZone.run(function () { - observer.next(result); - }); + currentZone.run(function () { return observer.next(result); }); } } ])); @@ -57,7 +55,7 @@ var MeteorObservable = (function () { }); }, onReady: function () { - currentZone.run(observer.next); + currentZone.run(function () { return observer.next(); }); } } ])); diff --git a/modules/minimongo-observable/meteor-observable.ts b/modules/minimongo-observable/meteor-observable.ts index bc71440..552fa18 100644 --- a/modules/minimongo-observable/meteor-observable.ts +++ b/modules/minimongo-observable/meteor-observable.ts @@ -24,9 +24,7 @@ export class MeteorObservable { observer.complete(); }); } else { - currentZone.run(() => { - observer.next(result); - }); + currentZone.run(() => observer.next(result)); } } ])); @@ -60,7 +58,7 @@ export class MeteorObservable { }); }, onReady: () => { - currentZone.run(observer.next); + currentZone.run(() => observer.next()); } } ])); From 6a2066ca79486a09f7cb2248a6b1bf43a2bfe073 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 23:19:04 +0300 Subject: [PATCH 10/11] chore(tests): Fixes for Observable feature tests --- tests/client/unit/meteor-observable.spec.ts | 10 -- tests/client/unit/to-observable.spec.ts | 108 ++++++++++++-------- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/tests/client/unit/meteor-observable.spec.ts b/tests/client/unit/meteor-observable.spec.ts index 88ef582..de890e7 100644 --- a/tests/client/unit/meteor-observable.spec.ts +++ b/tests/client/unit/meteor-observable.spec.ts @@ -39,16 +39,6 @@ describe('MeteorObservable', function () { }); }); - it("Should trigger the RxJS Observable 'complete' callback when got the server response", function(done) { - let spy = sinon.spy(); - let subscriptionHandler = MeteorObservable.call("testMethod").subscribe(function() {}, function() {}, () => { - spy(); - expect(spy.callCount).to.equal(1); - subscriptionHandler.unsubscribe(); - done(); - }); - }); - it("Should trigger the RxJS Observable 'error' callback when got the server error", function(done) { let spy = sinon.spy(); let subscriptionHandler = MeteorObservable.call("NON_EXISTING_METHOD").subscribe(function() {}, (e) => { diff --git a/tests/client/unit/to-observable.spec.ts b/tests/client/unit/to-observable.spec.ts index 5a7f862..73a2a1b 100644 --- a/tests/client/unit/to-observable.spec.ts +++ b/tests/client/unit/to-observable.spec.ts @@ -5,12 +5,12 @@ import {Observable} from "rxjs"; const expect = chai.expect; -describe('toObservable', function() { - let collection : Mongo.Collection; - let cursor : Mongo.Cursor; - let observable : ObservableCursor; +describe('toObservable', function () { + let collection: Mongo.Collection; + let cursor: Mongo.Cursor; + let observable: ObservableCursor; - beforeEach(function() { + beforeEach(function () { collection = new Mongo.Collection(null); collection.allow({ insert: function () { @@ -28,62 +28,73 @@ describe('toObservable', function() { observable = toObservable(cursor); }); - it ("Should wrap the Mongo.Cursor and return RxJS Observable", function() { + it("Should wrap the Mongo.Cursor and return RxJS Observable", function () { expect(observable instanceof Observable).to.equal(true); }); - it ("Should not use the actual Cursor 'observe' method without Observable subscription", function() { + it("Should not use the actual Cursor 'observe' method without Observable subscription", function () { let spy = sinon.spy(cursor, "observe"); expect(spy.called).to.equal(false); spy.restore(); }); - it ("Should use the actual Cursor 'observe' after using Observable subscription", function() { + it("Should use the actual Cursor 'observe' after using Observable subscription", function () { let spy = sinon.spy(cursor, "observe"); - let subscriptionHandler = observable.subscribe(() => {}); + let subscriptionHandler = observable.subscribe(() => { + }); expect(spy.calledOnce).to.equal(true); spy.restore(); subscriptionHandler.unsubscribe(); }); - it ("Should not trigger subscription callback when creating the subscription", function() { + it("Should not trigger subscription callback when creating the subscription", function () { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); expect(spy.called).to.equal(false); subscriptionHandler.unsubscribe(); }); - it ("Should trigger subscription callback when adding data to the collection", function() { + it("Should trigger subscription callback when adding data to the collection", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); collection.insert({test: true}); - expect(spy.calledOnce).to.equal(true); - subscriptionHandler.unsubscribe(); + + setTimeout(() => { + expect(spy.calledOnce).to.equal(true); + subscriptionHandler.unsubscribe(); + done(); + }, 100); + }); - it ("Should trigger subscription callback when removing data to the collection", function() { + it("Should trigger subscription callback when removing data to the collection", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); - let idToRemove = collection.insert({test: true}); collection.remove(idToRemove); - expect(spy.callCount).to.equal(2); - subscriptionHandler.unsubscribe(); + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should trigger subscription callback when updating data on the collection", function() { + it("Should trigger subscription callback when updating data on the collection", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); let idToUpdate = collection.insert({test: true}); collection.update({_id: idToUpdate}, {$set: {test: false}}); - expect(spy.callCount).to.equal(2); - subscriptionHandler.unsubscribe(); + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should trigger the subscription callback multiple times when inserting multiple objects", function() { + it("Should trigger the subscription callback multiple times when inserting multiple objects", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); @@ -91,58 +102,71 @@ describe('toObservable', function() { collection.insert({test: 2}); collection.insert({test: 3}); - expect(spy.callCount).to.equal(3); - subscriptionHandler.unsubscribe(); + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should NOT trigger the subscription callback when trying to update non-existing object", function() { + it("Should NOT trigger the subscription callback when trying to update non-existing object", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); collection.insert({test: 1}); collection.update({test: 'B'}, {$set: {test: 'C'}}); - expect(spy.callCount).to.equal(1); - subscriptionHandler.unsubscribe(); + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should NOT trigger the subscription callback when trying to remove non-existing object", function() { + it("Should NOT trigger the subscription callback when trying to remove non-existing object", function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); collection.insert({test: 1}); collection.remove({_id: "test"}); - expect(spy.callCount).to.equal(1); - subscriptionHandler.unsubscribe(); + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should stop the observation of the Mongo.Collection when disposing the Observable", function() { + it("Should stop the observation of the Mongo.Collection when disposing the Observable", function () { let stopSpy = sinon.spy(); - let spy = sinon.stub(cursor, "observe", function() { + let spy = sinon.stub(cursor, "observe", function () { return { stop: stopSpy } }); - let subscriptionHandler = observable.subscribe(function() {}); + let subscriptionHandler = observable.subscribe(function () {}); subscriptionHandler.unsubscribe(); expect(stopSpy.callCount).to.equal(1); spy.restore(); }); - it ("Should NOT trigger subscription callback when adding data to the non-reactive collection", function() { + it("Should NOT trigger subscription callback when adding data to the non-reactive collection", function (done) { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy); collection.insert({test: true}); collection.insert({test: true}); - expect(spy.callCount).to.equal(1); - subscriptionHandler.unsubscribe(); + + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); - it ("Should isReactive return false when calling nonReactive", function() { + it("Should isReactive return false when calling nonReactive", function () { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy); @@ -150,7 +174,7 @@ describe('toObservable', function() { subscriptionHandler.unsubscribe(); }); - it ("Should isReactive return true when not calling nonReactive", function() { + it("Should isReactive return true when not calling nonReactive", function () { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.subscribe(spy); @@ -158,7 +182,7 @@ describe('toObservable', function() { subscriptionHandler.unsubscribe(); }); - it ("Should trigger subscription callback when adding data to the non-reactive collection and calling reload", function() { + it("Should trigger subscription callback when adding data to the non-reactive collection and calling reload", function (done) { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy); @@ -170,7 +194,11 @@ describe('toObservable', function() { collection.insert({test: true}); collection.insert({test: true}); observable2.reload(); - expect(spy.callCount).to.equal(2); - subscriptionHandler.unsubscribe(); + + setTimeout(() => { + expect(spy.callCount).to.equal(1); + subscriptionHandler.unsubscribe(); + done(); + }, 100); }); }); \ No newline at end of file From cf2522577f321f152625d416ac33b5ade858bd72 Mon Sep 17 00:00:00 2001 From: dotansimha Date: Wed, 10 Aug 2016 23:24:06 +0300 Subject: [PATCH 11/11] chore(tests): Fixed lint issues of the tests files --- tests/client/unit/meteor-observable.spec.ts | 64 ++++++++++----------- tests/client/unit/to-observable.spec.ts | 44 +++++++------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/tests/client/unit/meteor-observable.spec.ts b/tests/client/unit/meteor-observable.spec.ts index de890e7..c09c5a0 100644 --- a/tests/client/unit/meteor-observable.spec.ts +++ b/tests/client/unit/meteor-observable.spec.ts @@ -1,47 +1,47 @@ import {chai} from 'meteor/practicalmeteor:chai'; import {sinon} from 'meteor/practicalmeteor:sinon'; -import {MeteorObservable, ObservableMeteorSubscription} from "angular2-meteor"; -import {Observable} from "rxjs"; +import {MeteorObservable, ObservableMeteorSubscription} from 'angular2-meteor'; +import {Observable} from 'rxjs'; const expect = chai.expect; describe('MeteorObservable', function () { - describe("call", function() { + describe('call', function() { - it("Should return RxJS Observable when using 'call'", function() { - let returnValue = MeteorObservable.call("testMethod"); + it('Should return RxJS Observable when using "call"', function() { + let returnValue = MeteorObservable.call('testMethod'); expect(returnValue instanceof Observable).to.equal(true); }); - it("Should NOT run the actual 'call' method without subscribing to the result", function() { - let spy = sinon.spy(Meteor, "call"); - MeteorObservable.call("testMethod"); + it('Should NOT run the actual "call" method without subscribing to the result', function() { + let spy = sinon.spy(Meteor, 'call'); + MeteorObservable.call('testMethod'); expect(spy.called).to.equal(false); spy.restore(); }); - it("Should run the actual 'call' method when subscribing to the result", function() { - let spy = sinon.spy(Meteor, "call"); - let subscriptionHandler = MeteorObservable.call("testMethod").subscribe(function() {}); + it('Should run the actual "call" method when subscribing to the result', function() { + let spy = sinon.spy(Meteor, 'call'); + let subscriptionHandler = MeteorObservable.call('testMethod').subscribe(function() {}); expect(spy.calledOnce).to.equal(true); spy.restore(); subscriptionHandler.unsubscribe(); }); - it("Should trigger the RxJS Observable 'next' callback when got the server response", function(done) { + it('Should trigger the RxJS Observable "next" callback when got the server response', function(done) { let spy = sinon.spy(); - let subscriptionHandler = MeteorObservable.call("testMethod").subscribe((serverResponse) => { + let subscriptionHandler = MeteorObservable.call('testMethod').subscribe((serverResponse) => { spy(); expect(spy.callCount).to.equal(1); - expect(serverResponse).to.equal("TEST_VALUE"); + expect(serverResponse).to.equal('TEST_VALUE'); subscriptionHandler.unsubscribe(); done(); }); }); - it("Should trigger the RxJS Observable 'error' callback when got the server error", function(done) { + it('Should trigger the RxJS Observable "error" callback when got the server error', function(done) { let spy = sinon.spy(); - let subscriptionHandler = MeteorObservable.call("NON_EXISTING_METHOD").subscribe(function() {}, (e) => { + let subscriptionHandler = MeteorObservable.call('NON_EXISTING_METHOD').subscribe(function() {}, (e) => { spy(); expect(spy.callCount).to.equal(1); expect(e instanceof Meteor.Error).to.equal(true); @@ -51,31 +51,31 @@ describe('MeteorObservable', function () { }); }); - describe("subscribe", function() { - it("Should return RxJS Observable when using 'subscribe'", function() { - let returnValue = MeteorObservable.subscribe("test"); + describe('subscribe', function() { + it('Should return RxJS Observable when using "subscribe"', function() { + let returnValue = MeteorObservable.subscribe('test'); expect(returnValue instanceof Observable).to.equal(true); }); - it("Should NOT run the actual 'subscribe' method without subscribing to the result", function() { - let spy = sinon.spy(Meteor, "subscribe"); - MeteorObservable.subscribe("test"); + it('Should NOT run the actual "subscribe" method without subscribing to the result', function() { + let spy = sinon.spy(Meteor, 'subscribe'); + MeteorObservable.subscribe('test'); expect(spy.called).to.equal(false); spy.restore(); }); - it("Should run the actual 'subscribe' method when subscribing to the result", function() { - let spy = sinon.spy(Meteor, "subscribe"); - let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(function() {}); + it('Should run the actual "subscribe" method when subscribing to the result', function() { + let spy = sinon.spy(Meteor, 'subscribe'); + let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(function() {}); expect(spy.called).to.equal(true); spy.restore(); subscriptionHandler.unsubscribe(); }); - it("Should call RxJS Observable 'next' callback when subscription is ready", function(done) { + it('Should call RxJS Observable "next" callback when subscription is ready', function(done) { let spy = sinon.spy(); - let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(() => { + let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(() => { spy(); expect(spy.callCount).to.equal(1); subscriptionHandler.unsubscribe(); @@ -83,14 +83,14 @@ describe('MeteorObservable', function () { }); }); - it("Should stop the Meteor subscription when unsubscribing to the RxJS Observable", function(done) { + it('Should stop the Meteor subscription when unsubscribing to the RxJS Observable', function(done) { function getSubscriptionsCount() { return Object.keys((Meteor).default_connection._subscriptions).length; } let baseSubscriptionsCount = getSubscriptionsCount(); - let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(() => { + let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(() => { expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount + 1); subscriptionHandler.unsubscribe(); expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount); @@ -99,15 +99,15 @@ describe('MeteorObservable', function () { }); - it("Should stop the Meteor subscription when calling stop of the Observable", function(done) { + it('Should stop the Meteor subscription when calling stop of the Observable', function(done) { function getSubscriptionsCount() { return Object.keys((Meteor).default_connection._subscriptions).length; } let baseSubscriptionsCount = getSubscriptionsCount(); - let obs : ObservableMeteorSubscription = MeteorObservable.subscribe("test"); - let subscriptionHandler = obs.subscribe(() => { + let obs : ObservableMeteorSubscription = MeteorObservable.subscribe('test'); + obs.subscribe(() => { expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount + 1); obs.stop(); expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount); diff --git a/tests/client/unit/to-observable.spec.ts b/tests/client/unit/to-observable.spec.ts index 73a2a1b..ed42559 100644 --- a/tests/client/unit/to-observable.spec.ts +++ b/tests/client/unit/to-observable.spec.ts @@ -1,7 +1,7 @@ import {toObservable, ObservableCursor} from 'angular2-meteor'; import {chai} from 'meteor/practicalmeteor:chai'; import {sinon} from 'meteor/practicalmeteor:sinon'; -import {Observable} from "rxjs"; +import {Observable} from 'rxjs'; const expect = chai.expect; @@ -16,10 +16,10 @@ describe('toObservable', function () { insert: function () { return true; }, - update: function () { + remove: function () { return true; }, - remove: function () { + update: function () { return true; } }); @@ -28,18 +28,18 @@ describe('toObservable', function () { observable = toObservable(cursor); }); - it("Should wrap the Mongo.Cursor and return RxJS Observable", function () { + it('Should wrap the Mongo.Cursor and return RxJS Observable', function () { expect(observable instanceof Observable).to.equal(true); }); - it("Should not use the actual Cursor 'observe' method without Observable subscription", function () { - let spy = sinon.spy(cursor, "observe"); + it('Should not use the actual Cursor "observe" method without Observable subscription', function () { + let spy = sinon.spy(cursor, 'observe'); expect(spy.called).to.equal(false); spy.restore(); }); - it("Should use the actual Cursor 'observe' after using Observable subscription", function () { - let spy = sinon.spy(cursor, "observe"); + it('Should use the actual Cursor "observe" after using Observable subscription', function () { + let spy = sinon.spy(cursor, 'observe'); let subscriptionHandler = observable.subscribe(() => { }); expect(spy.calledOnce).to.equal(true); @@ -47,14 +47,14 @@ describe('toObservable', function () { subscriptionHandler.unsubscribe(); }); - it("Should not trigger subscription callback when creating the subscription", function () { + it('Should not trigger subscription callback when creating the subscription', function () { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); expect(spy.called).to.equal(false); subscriptionHandler.unsubscribe(); }); - it("Should trigger subscription callback when adding data to the collection", function (done) { + it('Should trigger subscription callback when adding data to the collection', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); collection.insert({test: true}); @@ -67,7 +67,7 @@ describe('toObservable', function () { }); - it("Should trigger subscription callback when removing data to the collection", function (done) { + it('Should trigger subscription callback when removing data to the collection', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); let idToRemove = collection.insert({test: true}); @@ -80,7 +80,7 @@ describe('toObservable', function () { }, 100); }); - it("Should trigger subscription callback when updating data on the collection", function (done) { + it('Should trigger subscription callback when updating data on the collection', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); @@ -94,7 +94,7 @@ describe('toObservable', function () { }, 100); }); - it("Should trigger the subscription callback multiple times when inserting multiple objects", function (done) { + it('Should trigger the subscription callback multiple times when inserting multiple objects', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); @@ -109,7 +109,7 @@ describe('toObservable', function () { }, 100); }); - it("Should NOT trigger the subscription callback when trying to update non-existing object", function (done) { + it('Should NOT trigger the subscription callback when trying to update non-existing object', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); @@ -123,12 +123,12 @@ describe('toObservable', function () { }, 100); }); - it("Should NOT trigger the subscription callback when trying to remove non-existing object", function (done) { + it('Should NOT trigger the subscription callback when trying to remove non-existing object', function (done) { let spy = sinon.spy(); let subscriptionHandler = observable.subscribe(spy); collection.insert({test: 1}); - collection.remove({_id: "test"}); + collection.remove({_id: 'test'}); setTimeout(() => { expect(spy.callCount).to.equal(1); @@ -137,9 +137,9 @@ describe('toObservable', function () { }, 100); }); - it("Should stop the observation of the Mongo.Collection when disposing the Observable", function () { + it('Should stop the observation of the Mongo.Collection when disposing the Observable', function () { let stopSpy = sinon.spy(); - let spy = sinon.stub(cursor, "observe", function () { + let spy = sinon.stub(cursor, 'observe', function () { return { stop: stopSpy } @@ -152,7 +152,7 @@ describe('toObservable', function () { spy.restore(); }); - it("Should NOT trigger subscription callback when adding data to the non-reactive collection", function (done) { + it('Should NOT trigger subscription callback when adding data to the non-reactive collection', function (done) { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy); @@ -166,7 +166,7 @@ describe('toObservable', function () { }, 100); }); - it("Should isReactive return false when calling nonReactive", function () { + it('Should isReactive return false when calling nonReactive', function () { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy); @@ -174,7 +174,7 @@ describe('toObservable', function () { subscriptionHandler.unsubscribe(); }); - it("Should isReactive return true when not calling nonReactive", function () { + it('Should isReactive return true when not calling nonReactive', function () { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.subscribe(spy); @@ -182,7 +182,7 @@ describe('toObservable', function () { subscriptionHandler.unsubscribe(); }); - it("Should trigger subscription callback when adding data to the non-reactive collection and calling reload", function (done) { + it('Should trigger subscription callback when adding data to the non-reactive collection and calling reload', function (done) { let spy = sinon.spy(); let observable2 = toObservable(cursor); let subscriptionHandler = observable2.nonReactive().subscribe(spy);