├── .editorconfig ├── .gitignore ├── .npm └── package │ ├── .gitignore │ ├── README │ └── npm-shrinkwrap.json ├── .travis.yml ├── .versions ├── LICENSE.txt ├── README.md ├── chronos.js ├── package.js ├── unittests.js └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.js] 14 | indent_style = space 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .build* 2 | .idea 3 | -------------------------------------------------------------------------------- /.npm/package/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npm/package/README: -------------------------------------------------------------------------------- 1 | This directory and the files immediately inside it are automatically generated 2 | when you change this package's NPM dependencies. Commit the files in this 3 | directory (npm-shrinkwrap.json, .gitignore, and this README) to source control 4 | so that others run the same versions of sub-dependencies. 5 | 6 | You should NOT check in the node_modules directory that Meteor automatically 7 | creates; if you are using git, the .gitignore file tells git to ignore it. 8 | -------------------------------------------------------------------------------- /.npm/package/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "moment": { 4 | "version": "2.13.0", 5 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz", 6 | "from": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # using Spacejam for running tests 2 | # see: http://practicalmeteor.com/testing-meteor-packages-command-line-travis-ci/ 3 | 4 | language: node_js 5 | 6 | node_js: "0.10.29" 7 | 8 | install: 9 | - "curl https://install.meteor.com | /bin/sh" 10 | - "npm install -g spacejam" 11 | 12 | script: 13 | - "spacejam test-packages --driver-package=practicalmeteor:mocha-console-runner ./" 14 | -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | base64@1.0.3 2 | binary-heap@1.0.3 3 | callback-hook@1.0.3 4 | check@1.0.5 5 | ddp@1.1.0 6 | ejson@1.0.6 7 | geojson-utils@1.0.3 8 | id-map@1.0.3 9 | json@1.0.3 10 | local-test:remcoder:chronos@0.2.4 11 | logging@1.0.7 12 | meteor@1.1.6 13 | minimongo@1.0.8 14 | mongo@1.1.0 15 | ordered-dict@1.0.3 16 | random@1.0.3 17 | reactive-var@1.0.5 18 | remcoder:chronos@0.2.4 19 | retry@1.0.3 20 | tinytest@1.0.5 21 | tracker@1.0.7 22 | underscore@1.0.3 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Remco Veldkamp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chronos [![Build Status](https://travis-ci.org/remcoder/chronos.svg?branch=master)](https://travis-ci.org/remcoder/chronos) 2 | 3 | For a short introduction, see my [lightning talk at the Meteor Meetup](http://vimeo.com/129601361) in Amsterdam about Chronos. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | $ meteor add remcoder:chronos 9 | ``` 10 | 11 | ### API overview 12 | 13 | * __Chronos.date__ - a reactive replacement for `new Date()` 14 | * __Chronos.now__ - a reactive replacement for `Date.now()` 15 | * __Chronos.moment__ - a reactive replacement for `moment()` 16 | * __Chronos.update__ - trigger reactive updates with a single call 17 | * __Chronos.Timer__ - a simple reactive timer 18 | 19 | ## Chronos.date(interval) 20 | A reactive replacement for `new Date`. It returns a `Date` object and triggers reactive updates. 21 | Optionally pass an `interval` in milliseconds. The default is 1000ms (1 second). 22 | 23 | Usage: 24 | 25 | ```html 26 | 29 | ``` 30 | 31 | ```javascript 32 | Template.foo.helpers({ 33 | currentTime : function() { 34 | return Chronos.date(); // updates every second 35 | } 36 | }); 37 | ``` 38 | 39 | ## Chronos.now(interval) 40 | A reactive replacement for `Date.now`. It returns the milliseconds since the start of the epoch and triggers reactive updates. 41 | Optionally pass an `interval` in milliseconds. The default is 1000ms (1 second). 42 | 43 | Usage: 44 | 45 | ```html 46 | 49 | ``` 50 | 51 | ```javascript 52 | Template.foo.helpers({ 53 | millis : function() { 54 | return Chronos.now(); // updates every second 55 | } 56 | }); 57 | ``` 58 | 59 | ## Chronos.moment(args...) 60 | A reactive replacement for the global function `moment()` as provided by [moment.js](http://momentjs.com/). This reactive version will trigger live updates, for live timestamps and such. 61 | You'll need to include moment.js yourself (and the reason is that there are [several different versions of momentjs on Atmosphere](https://atmospherejs.com/?q=moment)). 62 | 63 | Usage: 64 | 65 | ```javascript 66 | // call with the same params as moment() 67 | Chronos.moment(/* arguments */); 68 | ``` 69 | 70 | Example template + helper: 71 | 72 | ```html 73 | 76 | ``` 77 | 78 | ```javascript 79 | var start = new Date(); 80 | 81 | Template.foo.helpers({ 82 | timeSpent : function() { 83 | return Chronos.moment(start).fromNow(); 84 | } 85 | }); 86 | ``` 87 | 88 | Example with autorun: 89 | 90 | ```javascript 91 | var timestamp = new Date(); 92 | 93 | Tracker.autorun(function() { 94 | // prints how long ago the timestamp was made, every second 95 | console.log(Chronos.moment(timestamp).fromNow()); 96 | }); 97 | ``` 98 | 99 | _Note: this uses a `Chronos.Timer` under the hood. This timer is started automatically when you call `.liveMoment`_ 100 | 101 | ## Chronos.update(interval) 102 | When called from inside a Blaze helper or other reactive context, it will setup a timer once and make the context dependent on the timer. What this means is that for example the helper will we re-run every time the timer updates. 103 | 104 | Usage: 105 | 106 | ```javascript 107 | // make context live updating. defaults to an interval of 1000m. 108 | Chronos.update(interval); 109 | ``` 110 | 111 | _It returns the `Chronos.Timer` that drives the updates._ 112 | 113 | Example template + helper: 114 | 115 | ```html 116 | 119 | ``` 120 | 121 | ```javascript 122 | Template.foo.helpers({ 123 | 124 | // returns a random number between 0 and 10, every second 125 | randomNumber : function() { 126 | Chronos.update(); 127 | return Math.round( Math.random() * 10 ); 128 | } 129 | }); 130 | ``` 131 | 132 | Example with autorun: 133 | 134 | ```javascript 135 | // this will create counter and logs it every second 136 | var count = 0; 137 | 138 | Tracker.autorun(function() { 139 | Chronos.update(); 140 | console.log(count); 141 | count++; 142 | }); 143 | ``` 144 | 145 | _Note: this uses a `Chronos.Timer` under the hood. This timer is started automatically when you call `.update`_ 146 | 147 | 148 | 149 | ## Chronos.Timer() 150 | usage: 151 | 152 | ```javascript 153 | // create new timer. defaults to an interval of 1000ms 154 | var timer = new Chronos.Timer(interval); 155 | ``` 156 | 157 | The timer exposes the `time` property, which is a [ReactiveVar](http://docs.meteor.com/#/full/reactivevar) and it holds the current time. 158 | Getting the time value is reactive so it will trigger re-runs whenever the timer produces an update. 159 | 160 | ```javascript 161 | timer.time.get(); 162 | ``` 163 | 164 | Example template + helper: 165 | 166 | ```html 167 | 170 | ``` 171 | 172 | ```javascript 173 | var timer = new Chronos.Timer(100); 174 | 175 | Template.timer.helpers({ 176 | 177 | // counts from 0 to 10 in 10 seconds 178 | time: function () { 179 | return ((timer.time.get() // get the current time 180 | / 1000) // convert ms to seconds 181 | % 10) // reset every 10 seconds 182 | .toFixed(0); // drop any decimals 183 | } 184 | }); 185 | ``` 186 | 187 | Example with autorun: 188 | 189 | ```javascript 190 | // prints the current time every 2 seconds 191 | var timer = new Chronos.Timer(2000); 192 | 193 | Tracker.autorun(function() { 194 | console.log(timer.time.get()); 195 | }); 196 | 197 | timer.start(); 198 | ``` 199 | 200 | ### Chronos.Timer.start() 201 | Starts the timer (by kicking off a setInterval loop). 202 | 203 | Usage: 204 | 205 | ```javascript 206 | timer.start(); 207 | ``` 208 | 209 | ### Chronos.Timer.stop() 210 | Stops the timer. 211 | 212 | Usage: 213 | 214 | ```javascript 215 | timer.stop(); 216 | ``` 217 | 218 | ## License 219 | 220 | [MIT License](LICENSE.txt) 221 | 222 | ## Changelog 223 | - 0.5.0 224 | - add new method `Chronos.now()`, which is a reactive replacement for `Date.now()` 225 | - fixed a build error which prevented Chronos to work on windows (there was a colon in a filename) 226 | - renamed some methods to stay closer to their non-reactive counterparts (with aliases in place to prevent breakage): 227 | - Chronos.liveMoment() -> Chronos.moment() 228 | - Chronos.liveUpdate() -> Chronos.update() 229 | - Chronos.currentTime() -> Chronos.date() 230 | - 0.4.1 231 | - fixed regression where the momentjs package from Atmosphere didn't work anymore 232 | - 0.4.0 233 | - fixed a bug causing a ReferenceError when `liveMoment` is called and moment is imported as a module 234 | ([#10](https://github.com/remcoder/chronos/issues/10)) 235 | thx to [dylanmcgowan](https://github.com/dylanmcgowan) 236 | - 0.3.1 237 | - fixed a bug where `destroy()` would sometimes be called twice, resulting in a TypeError ([#7](https://github.com/remcoder/chronos/issues/7)) 238 | thx to [MichelFloyd](https://github.com/MichelFloyd) 239 | - 0.3.0 240 | - added `currentTime()` a reactive replacement for `new Date` 241 | - no longer throws an exception when used outside a reactive context. 242 | - 0.2.x 243 | - bugfixes 244 | - 0.2.0 245 | - Instantiating a Chronos.Timer will not start the timer immediately anymore. 246 | -------------------------------------------------------------------------------- /chronos.js: -------------------------------------------------------------------------------- 1 | let moment; 2 | 3 | // if moment is not installed, fine. We don't require it as a hard dependency 4 | try { 5 | moment = require('moment'); 6 | } 7 | catch(e) { 8 | } 9 | 10 | const _timers = {}; 11 | 12 | function Timer(interval) { 13 | this.interval = interval || 1000; 14 | this.time = new ReactiveVar(0); 15 | } 16 | 17 | Timer.prototype.start = function() { 18 | if (this._timer) throw new Error('Trying to start Chronos.Timer but it is already running.'); 19 | this.time.set(new Date()); 20 | 21 | 22 | this._timer = setInterval(Meteor.bindEnvironment(function() { 23 | //console.log('tick', this._timer); 24 | this.time.set(new Date()); 25 | 26 | }.bind(this)), this.interval); 27 | }; 28 | 29 | Timer.prototype.stop = function() { 30 | //console.log('stopping timer'); 31 | clearInterval(this._timer); 32 | this._timer = null; 33 | }; 34 | 35 | function _update(interval) { 36 | // get current reactive context 37 | const comp = Tracker.currentComputation; 38 | if (!comp) 39 | return; // no nothing when used outside a reactive context 40 | 41 | // only create one timer per reactive context to prevent stacking of timers 42 | const cid = comp && comp._id; 43 | if (!_timers[cid]) { 44 | const timer = new Timer(interval); 45 | _timers[cid] = timer; 46 | 47 | // add destroy method that stops the timer and removes itself from the list 48 | timer.destroy = function() { 49 | timer.stop(); 50 | delete _timers[cid]; 51 | }; 52 | 53 | timer.start(); 54 | } 55 | 56 | // make sure to stop and delete the attached timer when the computation is stopped 57 | comp.onInvalidate(function() { 58 | //console.log('onInvalidated',comp); 59 | if (comp.stopped && _timers[cid]) { 60 | //console.log('computation stopped'); 61 | _timers[cid].destroy(); 62 | } 63 | }); 64 | 65 | _timers[cid].time.dep.depend(comp); // make dependent on time 66 | 67 | //console.log(_timers); 68 | return _timers[cid]; 69 | } 70 | 71 | // reactive version of moment() 72 | // please install moment separately 73 | // example usage: Chronos.moment(someTimestamp).format('ss'); 74 | function _moment(/* arguments */) { 75 | if (!moment) throw new Error('moment not found. Please install it first'); 76 | 77 | _update(); 78 | return moment.apply(null, arguments); 79 | } 80 | 81 | // reactive version of new Date() get the current date/time 82 | function _date(interval) { 83 | _update(interval); 84 | return new Date(); 85 | } 86 | 87 | // reactive version of Date.now(). get the current # of milliseconds since the start of the epoch 88 | function _now(interval) { 89 | _update(interval); 90 | return Date.now(); 91 | } 92 | 93 | // export global 94 | Chronos = { 95 | 96 | // a simple reactive timer 97 | // usage: var timer = new Timer(); 98 | // get current time: timer.time.get(); 99 | Timer, 100 | 101 | // handy util func for making reactive contexts live updating in time 102 | // usage: simply call Chronos.update() in your helper to make it execute 103 | // every interval 104 | update: _update, 105 | 106 | // reactive version of new Date() get the current date/time 107 | date : _date, 108 | 109 | // reactive version of Date.now(). get the current # of milliseconds since the start of the epoch 110 | now : _now, 111 | 112 | // reactive version of moment() 113 | // please install moment separately 114 | // example usage: Chronos.moment(someTimestamp).format('ss'); 115 | moment : _moment, 116 | 117 | // for debugging and testing 118 | _timers, 119 | 120 | // deprecated. but kept for backwards compatibility 121 | liveUpdate : _update, 122 | currentTime : _date, 123 | liveMoment : _moment 124 | }; -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'remcoder:chronos', 3 | summary: 'Reactive time utilities. Includes reactive replacements for new Date(), Date.now() and moment()', 4 | version: '0.5.0', 5 | git: 'https://github.com/remcoder/chronos' 6 | }); 7 | 8 | Package.onUse(function(api) { 9 | api.versionsFrom('1.3'); 10 | api.use('ecmascript'); 11 | api.use('tracker'); 12 | api.use('reactive-var'); 13 | api.use('tracker'); 14 | api.use('zodiase:function-bind@0.0.1'); 15 | Npm.depends({ 16 | moment: '2.13.0' 17 | }); 18 | api.export('Chronos'); 19 | api.addFiles('chronos.js'); 20 | }); 21 | 22 | Package.onTest(function(api) { 23 | api.use('ecmascript'); 24 | api.use('tracker'); 25 | Npm.depends({ 26 | moment: '2.13.0' 27 | }); 28 | api.use('remcoder:chronos'); 29 | api.use('practicalmeteor:mocha'); 30 | api.use('practicalmeteor:chai'); 31 | 32 | api.mainModule('unittests.js'); 33 | }); 34 | -------------------------------------------------------------------------------- /unittests.js: -------------------------------------------------------------------------------- 1 | import { chai } from 'meteor/practicalmeteor:chai'; 2 | 3 | const moment = require('moment'); 4 | 5 | describe('timer creation I', function () { 6 | it('invoking the constructor of Chronos.Timer should result in an instance of Chronos.Timer', function () { 7 | var timer = new Chronos.Timer(); 8 | chai.assert.instanceOf(timer, Chronos.Timer); 9 | }) 10 | }); 11 | 12 | describe('timer creation II', function () { 13 | it('timer shouldn\'t start immediately', function() { 14 | var timer = new Chronos.Timer(); 15 | chai.assert.isUndefined(timer._timer, 'timer._timer should not be set '); 16 | }); 17 | }); 18 | 19 | describe('timer start', function () { 20 | it('timer should have handle when started', function() { 21 | var timer = new Chronos.Timer(); 22 | timer.start(); 23 | chai.assert.isTrue( !!timer._timer ); 24 | }) 25 | }); 26 | 27 | 28 | describe('reactive updates I',function() { 29 | 30 | let count; 31 | before(function(done) { 32 | var timer = new Chronos.Timer(); 33 | 34 | count = 0; 35 | Tracker.autorun(Meteor.bindEnvironment(function (c) { 36 | timer.time.get(); 37 | count++; 38 | if (count > 1) { 39 | timer.stop(); 40 | done(); 41 | } 42 | })); 43 | 44 | timer.start(); 45 | }); 46 | 47 | it('getting the time should trigger reactive updates', function() { 48 | chai.assert(count>1); 49 | }); 50 | }); 51 | 52 | describe('reactive updates II',function() { 53 | let count; 54 | 55 | before(function(done) { 56 | var timer = new Chronos.Timer(); 57 | 58 | count = 0; 59 | Tracker.autorun(Meteor.bindEnvironment(function (c) { 60 | timer.time.dep.depend(); 61 | count++; 62 | if (count > 1) { 63 | timer.stop(); 64 | done(); 65 | } 66 | })); 67 | 68 | timer.start(); 69 | 70 | }); 71 | 72 | it('calling the underlying Dependency should trigger reactive updates', function () { 73 | chai.assert(count>1); 74 | }); 75 | 76 | }); 77 | 78 | describe('Chronos.update', function() { 79 | let count; 80 | 81 | before(function(done) { 82 | 83 | count = 0; 84 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 85 | var timer = Chronos.update(100); 86 | 87 | count++; 88 | if (count > 1) { 89 | timer.destroy(); 90 | done(); 91 | } 92 | })); 93 | }); 94 | 95 | it('Chronos.update should trigger reactive updates', function() { 96 | chai.assert(count>1); 97 | }); 98 | }); 99 | 100 | describe('Backwards compatibility I', function() { 101 | let count; 102 | 103 | before(function(done) { 104 | 105 | count = 0; 106 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 107 | var timer = Chronos.liveUpdate(100); 108 | 109 | count++; 110 | if (count > 1) { 111 | timer.destroy(); 112 | done(); 113 | } 114 | })); 115 | }); 116 | 117 | it('Chronos.liveUpdate should trigger reactive updates', function() { 118 | chai.assert(count>1); 119 | }); 120 | }); 121 | 122 | describe('Timer start II', function() { 123 | 124 | it('An already started Timer should not be able to start', function() { 125 | var timer = new Chronos.Timer(); 126 | timer.start(); 127 | chai.assert.throws(function () { 128 | timer.start(); 129 | }); 130 | }); 131 | }); 132 | 133 | describe('Destroying a timer', function() { 134 | var count = 0; 135 | before(function(done) { 136 | 137 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 138 | 139 | var timer = Chronos.update(10); 140 | 141 | if (count == 1) { 142 | timer.destroy(); 143 | } 144 | 145 | count++; 146 | 147 | })); 148 | 149 | Meteor.setTimeout(done, 100); 150 | }); 151 | 152 | it('A Chronos.update timer should be destroyable', function() { 153 | 154 | chai.assert.equal( Object.keys(Chronos._timers).length, 0, 'there should be no more timers now' ); 155 | 156 | chai.assert.equal( count, 2 ); 157 | }); 158 | }); 159 | 160 | 161 | describe('Chronos.date', function () { 162 | 163 | it('Chronos.date should return a Date object', function() { 164 | var reactiveTime = Chronos.date(); 165 | chai.assert.instanceOf(reactiveTime, Date); 166 | }); 167 | }); 168 | 169 | describe('Chronos.date II', function() { 170 | 171 | it('Chronos.date should return same time as new Date()', function() { 172 | var normalTime, reactiveTime; 173 | 174 | Tracker.autorun(function(c) { 175 | 176 | normalTime = new Date().getTime(); 177 | reactiveTime = Chronos.date().getTime(); 178 | 179 | c.stop(); 180 | }); 181 | 182 | chai.assert.closeTo( reactiveTime, normalTime, 2), 'there shouldn\'t be more than a millisecond difference'; 183 | }); 184 | }); 185 | 186 | describe('Chronos.date reactivity', function() { 187 | 188 | let count = 0; 189 | before(function(done) { 190 | 191 | 192 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 193 | Chronos.date(10); 194 | 195 | count++; 196 | if (count == 2) { 197 | c.stop(); 198 | done(); 199 | } 200 | })); 201 | 202 | }); 203 | 204 | it('Chronos.date should trigger reactive updates', function() { 205 | chai.assert.equal(count, 2); 206 | }); 207 | }); 208 | 209 | describe('Chronos.now', function () { 210 | 211 | it('Chronos.now should return a Number ', function() { 212 | var reactiveTime = Chronos.now(); 213 | chai.assert.isNumber(reactiveTime, Date); 214 | }); 215 | }); 216 | 217 | describe('Chronos.now II', function() { 218 | 219 | it('Chronos.now should return same time as Date.now()', function() { 220 | var normalTime, reactiveTime; 221 | 222 | Tracker.autorun(function(c) { 223 | 224 | normalTime = Date.now(); 225 | reactiveTime = Chronos.now(); 226 | 227 | c.stop(); 228 | }); 229 | 230 | chai.assert.closeTo( reactiveTime, normalTime, 2), 'there shouldn\'t be more than a millisecond difference'; 231 | }); 232 | }); 233 | 234 | describe('Chronos.now reactivity', function() { 235 | 236 | let count = 0; 237 | before(function(done) { 238 | 239 | 240 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 241 | Chronos.now(10); 242 | 243 | count++; 244 | if (count == 2) { 245 | c.stop(); 246 | done(); 247 | } 248 | })); 249 | 250 | }); 251 | 252 | it('Chronos.now should trigger reactive updates', function() { 253 | chai.assert.equal(count, 2); 254 | }); 255 | }); 256 | 257 | describe('Stopping the computation', function() { 258 | 259 | let count = 0; 260 | 261 | before(function (done) { 262 | 263 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 264 | 265 | Chronos.update(100); 266 | 267 | if (count > 0) 268 | c.stop(); 269 | 270 | count++; 271 | 272 | })); 273 | 274 | Meteor.setTimeout(done, 400); 275 | 276 | }); 277 | 278 | it('Chronos.update timer should be destroyed when computation is stopped', function() { 279 | chai.assert.equal(count, 2); 280 | }); 281 | }); 282 | 283 | 284 | describe('Stopping the computation II', function() { 285 | 286 | let count = 0; 287 | 288 | before(function (done) { 289 | 290 | Tracker.autorun(Meteor.bindEnvironment(function(c) { 291 | 292 | Chronos.date(100); 293 | 294 | if (count > 0) 295 | c.stop(); 296 | 297 | count++; 298 | 299 | })); 300 | 301 | Meteor.setTimeout(done, 400); 302 | 303 | }); 304 | 305 | it('Chronos.date timer should be destroyed when computation is stopped', function() { 306 | chai.assert.equal(count, 2); 307 | }); 308 | }); 309 | 310 | 311 | describe('Chronos.moment', function () { 312 | it('Chronos.moment should return a moment instance', function() { 313 | var reactiveMoment = Chronos.moment(); 314 | // chai.assert.instanceOf(reactiveMoment, moment().constructor); 315 | }); 316 | }); 317 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | [ 4 | "meteor", 5 | "1.1.3" 6 | ], 7 | [ 8 | "reactive-var", 9 | "1.0.3" 10 | ], 11 | [ 12 | "tracker", 13 | "1.0.3" 14 | ], 15 | [ 16 | "underscore", 17 | "1.0.1" 18 | ] 19 | ], 20 | "pluginDependencies": [], 21 | "toolVersion": "meteor-tool@1.0.35", 22 | "format": "1.0" 23 | } --------------------------------------------------------------------------------