node-schedule 0.5.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.npmignore CHANGED
@@ -1,6 +1,2 @@
1
- coverage
2
- node_modules
3
- node-schedule.tmproj
4
- .DS_Store
5
- npm-debug.log
6
-
1
+ *.sublime*
2
+ .npmrc
@@ -0,0 +1,31 @@
1
+ ## Rules
2
+ 1. **No `--force` pushes** or modifying the git history in any way
3
+ 2. Follow existing code style
4
+ 3. Pull requests with tests are much more likely to be accepted
5
+ 4. Follow the guidelines below
6
+
7
+ ## Bugfix or Feature?
8
+
9
+ This project uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). Simply put, you need to decide if your contribution will be a bug fix that could be released as a patch, or a feature that will end up being a minor or major release.
10
+
11
+ ### Found a bug that can be fixed without affecting the API?
12
+
13
+ 1. **Fork** this repo
14
+ 2. Create a new branch from `master` to work in
15
+ 3. **Add tests** if needed
16
+ 4. Make sure your code **lints** by running `npm run lint`
17
+ 5. Make sure your code **passes tests** by running `npm test`
18
+ 6. Submit a **pull request** against the `master` branch
19
+
20
+ ### New feature or anything that would result in a change to the API?
21
+
22
+ 1. **Fork** this repo
23
+ 2. Create a new branch from `develop` to work in
24
+ 3. **Add tests** to as needed
25
+ 4. Make sure your code **lints** by running `npm run lint`
26
+ 5. Make sure your code **passes tests** by running `npm test`
27
+ 6. Submit a **pull request** against the `develop` branch
28
+
29
+ ## Releases
30
+
31
+ Declaring formal releases remains the prerogative of the project maintainer.
package/README.md CHANGED
@@ -1,28 +1,194 @@
1
- # node-schedule
1
+ # Node Schedule
2
2
 
3
- [![NPM version](http://img.shields.io/npm/v/node-schedule.svg)](https://www.npmjs.com/package/node-schedule) [![Downloads](https://img.shields.io/npm/dm/node-schedule.svg)](https://www.npmjs.com/package/node-schedule) [![Build Status](https://travis-ci.org/node-schedule/node-schedule.svg?branch=master)](https://travis-ci.org/node-schedule/node-schedule) [![Join the chat at https://gitter.im/node-schedule/node-schedule](https://img.shields.io/badge/gitter-chat-green.svg)](https://gitter.im/node-schedule/node-schedule?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
+ [![NPM version](http://img.shields.io/npm/v/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
4
+ [![Downloads](https://img.shields.io/npm/dm/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
5
+ [![Build Status](https://travis-ci.org/node-schedule/node-schedule.svg?branch=master)](https://travis-ci.org/node-schedule/node-schedule)
6
+ [![Join the chat at https://gitter.im/node-schedule/node-schedule](https://img.shields.io/badge/gitter-chat-green.svg)](https://gitter.im/node-schedule/node-schedule?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
7
 
5
8
  [![NPM](https://nodei.co/npm/node-schedule.png?downloads=true)](https://nodei.co/npm/node-schedule/)
6
9
 
7
- >__Announcement:__ Node Schedule is looking for add additional collaborators with commit access. If you are actively involved in open source, ping [Tejas Manohar](http://tejas.io) (via [email](mailto:me@tejas.io), [Twitter](https://twitter.com/tejasmanohar), etc.) to express interest. Those who already contribute to the project are preferred.
10
+ >__Announcement:__ Node Schedule is looking for add additional collaborators
11
+ with commit access. If you are actively involved in open source,
12
+ ping [Tejas Manohar] via [email](mailto:me@tejas.io) to express interest.
13
+ Those who already contribute to the project are preferred.
8
14
 
9
- node-schedule is a flexible cron-like and not-cron-like job scheduler for Node.js. It allows you to schedule jobs (arbitrary functions) for execution at specific dates, with optional recurrence rules. It only uses a single timer at any given time (rather than reevaluating upcoming jobs every second/minute).
10
-
11
- Read more about the module's core functions on the [About](https://github.com/node-schedule/node-schedule/wiki/About) page of the wiki.
15
+ Node Schedule is a flexible cron-like and not-cron-like job scheduler for Node.js.
16
+ It allows you to schedule jobs (arbitrary functions) for execution at
17
+ specific dates, with optional recurrence rules. It only uses a single timer
18
+ at any given time (rather than reevaluating upcoming jobs every second/minute).
12
19
 
13
20
  ## Usage
14
21
 
15
- Check out our wonderful [wiki] for usage instructions.
22
+ ### Installation
16
23
 
24
+ You can install using [npm](https://www.npmjs.com/package/node-schedule).
17
25
 
18
- ## Contributing
26
+ ```
27
+ npm install node-schedule
28
+ ```
29
+
30
+ ### Overview
31
+
32
+ Node Schedule is for time-based scheduling, not interval-based scheduling.
33
+ While you can easily bend it to your will, if you only want to do something like
34
+ "run this function every 5 minutes", you'll find `setInterval` much easier to use,
35
+ and far more appropriate. But if you want to, say, "run this function at the :20
36
+ and :50 of every hour on the third Tuesday of every month," you'll find that
37
+ Node Schedule suits your needs better. Additionally, Node Schedule has Windows
38
+ support unlike true cron since the node runtime is now fully supported.
39
+
40
+ Note that Node Schedule is designed for in-process scheduling, i.e. scheduled jobs
41
+ will only fire as long as your script is running, and the schedule will disappear
42
+ when execution completes. If you need to schedule jobs that will persist even when
43
+ your script *isn't* running, consider using actual [cron].
44
+
45
+ ### Jobs and Scheduling
46
+
47
+ Every scheduled job in Node Schedule is represented by a `Job` object. You can
48
+ create jobs manually, then execute the `schedule()` method to apply a schedule,
49
+ or use the convenience function `scheduleJob()` as demonstrated below.
50
+
51
+ `Job` objects are `EventEmitter`'s, and emit a `run` event after each execution.
52
+ They also emit a `scheduled` event each time they're scheduled to run, and a
53
+ `canceled` event when an invocation is canceled before it's executed (both events
54
+ receive a JavaScript date object as a parameter). Note that jobs are scheduled the
55
+ first time immediately, so if you create a job using the `scheduleJob()`
56
+ convenience method, you'll miss the first `scheduled` event. Also note that
57
+ `canceled` is the single-L American spelling.
58
+
59
+ ### Cron-style Scheduling
60
+
61
+ The cron format consists of:
62
+ ```
63
+ * * * * * *
64
+ ┬ ┬ ┬ ┬ ┬ ┬
65
+ │ │ │ │ │ |
66
+ │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
67
+ │ │ │ │ └───── month (1 - 12)
68
+ │ │ │ └────────── day of month (1 - 31)
69
+ │ │ └─────────────── hour (0 - 23)
70
+ │ └──────────────────── minute (0 - 59)
71
+ └───────────────────────── second (0 - 59, OPTIONAL)
72
+ ```
73
+
74
+ Examples with the cron format:
75
+
76
+ ```js
77
+ var schedule = require('node-schedule');
78
+
79
+ var j = schedule.scheduleJob('42 * * * *', function(){
80
+ console.log('The answer to life, the universe, and everything!');
81
+ });
82
+ ```
83
+
84
+ And:
85
+
86
+ ```js
87
+ var j = schedule.scheduleJob('0 17 ? * 0,4-6', function(){
88
+ console.log('Today is recognized by Rebecca Black!');
89
+ });
90
+ ```
91
+
92
+ Execute a cron job every 5 Minutes = */5 * * * *
93
+
94
+ #### Unsupported Cron Features
95
+
96
+ Currently, `W` (nearest weekday), `L` (last day of month/week), and `#` (nth weekday
97
+ of the month) are not supported. Most other features supported by popular cron
98
+ implementations should work just fine.
99
+
100
+ [cron-parser] is used to parse crontab instructions.
19
101
 
20
- This module was originally developed by [Matt Patenaude], and is now maintained by [Tejas Manohar] and [other wonderful contributors].
102
+ ### Date-based Scheduling
103
+
104
+ Say you very specifically want a function to execute at 5:30am on December 21, 2012.
105
+ Remember - in JavaScript - 0 - January, 11 - December.
106
+
107
+ ```js
108
+ var schedule = require('node-schedule');
109
+ var date = new Date(2012, 11, 21, 5, 30, 0);
110
+
111
+ var j = schedule.scheduleJob(date, function(){
112
+ console.log('The world is going to end today.');
113
+ });
114
+ ```
115
+
116
+ You can invalidate the job with the `cancel()` method:
117
+
118
+ ```js
119
+ j.cancel();
120
+ ```
121
+
122
+ To use current data in the future you can use binding:
123
+
124
+ ```js
125
+ var schedule = require('node-schedule');
126
+ var date = new Date(2012, 11, 21, 5, 30, 0);
127
+ var x = 'Tada!';
128
+ var j = schedule.scheduleJob(date, function(y){
129
+ console.log(y);
130
+ }.bind(null,x));
131
+ x = 'Changing Data';
132
+ ```
133
+ This will log 'Tada!' when the scheduled Job runs, rather than 'Changing Data',
134
+ which x changes to immediately after scheduling.
135
+
136
+ ### Recurrence Rule Scheduling
137
+
138
+ You can build recurrence rules to specify when a job should recur. For instance,
139
+ consider this rule, which executes the function every hour at 42 minutes after the hour:
140
+
141
+ ```js
142
+ var schedule = require('node-schedule');
143
+
144
+ var rule = new schedule.RecurrenceRule();
145
+ rule.minute = 42;
146
+
147
+ var j = schedule.scheduleJob(rule, function(){
148
+ console.log('The answer to life, the universe, and everything!');
149
+ });
150
+ ```
151
+
152
+ You can also use arrays to specify a list of acceptable values, and the `Range`
153
+ object to specify a range of start and end values, with an optional step parameter.
154
+ For instance, this will print a message on Thursday, Friday, Saturday, and Sunday at 5pm:
155
+
156
+ ```js
157
+ var rule = new schedule.RecurrenceRule();
158
+ rule.dayOfWeek = [0, new schedule.Range(4, 6)];
159
+ rule.hour = 17;
160
+ rule.minute = 0;
161
+
162
+ var j = schedule.scheduleJob(rule, function(){
163
+ console.log('Today is recognized by Rebecca Black!');
164
+ });
165
+ ```
166
+
167
+ > **Note**: It's worth noting that the default value of a component of a recurrence rule is
168
+ `null` (except for seconds, which is 0 for familiarity with cron). *If we did not
169
+ explicitly set `minute` to 0 above, the message would have instead been logged at
170
+ 5:00pm, 5:01pm, 5:02pm, ..., 5:59pm.* Probably not what you want.
171
+
172
+ #### Object Literal Syntax
173
+
174
+ To make things a little easier, an object literal syntax is also supported, like
175
+ in this example which will log a message every Sunday at 2:30pm:
176
+
177
+ ```js
178
+ var j = schedule.scheduleJob({hour: 14, minute: 30, dayOfWeek: 0}, function(){
179
+ console.log('Time for tea!');
180
+ });
181
+ ```
182
+
183
+ ## Contributing
21
184
 
22
- We'd love to get your contributions. Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit.
185
+ This module was originally developed by [Matt Patenaude], and is now maintained by
186
+ [Tejas Manohar] and [other wonderful contributors].
23
187
 
24
- Before jumping in, check out our [Contributing](https://github.com/node-schedule/node-schedule/wiki/Contributing) page on the wiki!
188
+ We'd love to get your contributions. Individuals making significant and valuable
189
+ contributions are given commit-access to the project to contribute as they see fit.
25
190
 
191
+ Before jumping in, check out our [Contributing] page guide!
26
192
 
27
193
  ## Copyright and license
28
194
 
@@ -32,9 +198,10 @@ Licensed under the **[MIT License] [license]**.
32
198
 
33
199
 
34
200
  [cron]: http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
35
- [wiki]: https://github.com/node-schedule/node-schedule/wiki
36
- [contributing]: https://github.com/node-schedule/node-schedule/blob/master/CONTRIBUTING.md
201
+ [Contributing]: https://github.com/node-schedule/node-schedule/blob/master/CONTRIBUTING.md
37
202
  [Matt Patenaude]: https://github.com/mattpat
203
+ [Tejas Manohar]: http://tejas.io
38
204
  [license]: https://github.com/node-schedule/node-schedule/blob/master/LICENSE
39
205
  [Tejas Manohar]: https://github.com/tejasmanohar
40
206
  [other wonderful contributors]: https://github.com/node-schedule/node-schedule/graphs/contributors
207
+ [cron-parser]: https://github.com/harrisiirak/cron-parser
package/lib/schedule.js CHANGED
@@ -8,17 +8,26 @@
8
8
 
9
9
  var events = require('events'),
10
10
  util = require('util'),
11
- increment = require('./increment.js'),
12
11
  cronParser = require('cron-parser'),
12
+ CronDate = require('cron-parser/lib/date'),
13
13
  lt = require('long-timeout');
14
14
 
15
15
  /* Job object */
16
16
  var anonJobCounter = 0;
17
17
 
18
+ function isValidDate(date) {
19
+ // Taken from http://stackoverflow.com/a/12372720/1562178
20
+ // If getTime() returns NaN it'll return false anyway
21
+ return date.getTime() === date.getTime();
22
+ }
23
+
18
24
  function Job(name, job, callback) {
19
25
  // setup a private pendingInvocations variable
20
26
  var pendingInvocations = [];
21
27
 
28
+ //setup a private number of invocations variable
29
+ var triggeredJobs = 0;
30
+
22
31
  // Set scope vars
23
32
  var jobName = name && typeof name === 'string' ? name : '<Anonymous Job ' + (++anonJobCounter) + '>';
24
33
  this.job = name && typeof name === 'function' ? name : job;
@@ -33,10 +42,12 @@ function Job(name, job, callback) {
33
42
  }
34
43
 
35
44
  // Check for generator
36
- if (typeof this.job === 'function' && this.job.prototype.next) {
45
+ if (typeof this.job === 'function' &&
46
+ this.job.prototype &&
47
+ this.job.prototype.next) {
37
48
  this.job = function() {
38
49
  return this.next().value;
39
- }.bind(this.job());
50
+ }.bind(this.job.call(this));
40
51
  }
41
52
 
42
53
  // define properties
@@ -65,6 +76,12 @@ function Job(name, job, callback) {
65
76
 
66
77
  return false;
67
78
  };
79
+ this.triggeredJobs = function() {
80
+ return triggeredJobs;
81
+ };
82
+ this.setTriggeredJobs = function(triggeredJob) {
83
+ triggeredJobs = triggeredJob;
84
+ };
68
85
  this.cancel = function(reschedule) {
69
86
  reschedule = (typeof reschedule == 'boolean') ? reschedule : false;
70
87
 
@@ -92,7 +109,7 @@ function Job(name, job, callback) {
92
109
  // remove from scheduledJobs if reschedule === false
93
110
  if (!reschedule) {
94
111
  if (this.name) {
95
- scheduledJobs[this.name] = null;
112
+ delete scheduledJobs[this.name];
96
113
  }
97
114
  }
98
115
 
@@ -119,6 +136,26 @@ function Job(name, job, callback) {
119
136
 
120
137
  return true;
121
138
  };
139
+ this.reschedule = function(spec) {
140
+ var inv;
141
+ var cInvs = pendingInvocations.slice();
142
+
143
+ for (var j = 0; j < cInvs.length; j++) {
144
+ inv = cInvs[j];
145
+
146
+ cancelInvocation(inv);
147
+ }
148
+
149
+ pendingInvocations = [];
150
+
151
+ if (this.schedule(spec)) {
152
+ this.setTriggeredJobs(0);
153
+ return true;
154
+ } else {
155
+ pendingInvocations = cInvs;
156
+ return false;
157
+ }
158
+ };
122
159
  this.nextInvocation = function() {
123
160
  if (!pendingInvocations.length) {
124
161
  return null;
@@ -134,6 +171,7 @@ util.inherits(Job, events.EventEmitter);
134
171
 
135
172
  Job.prototype.invoke = function() {
136
173
  if (typeof this.job == 'function') {
174
+ this.setTriggeredJobs(this.triggeredJobs() + 1);
137
175
  this.job();
138
176
  } else {
139
177
  this.job.execute();
@@ -161,10 +199,12 @@ Job.prototype.schedule = function(spec) {
161
199
  spec = new Date(spec);
162
200
  }
163
201
 
164
- if (spec instanceof Date) {
165
- inv = new Invocation(self, spec);
166
- scheduleInvocation(inv);
167
- success = self.trackInvocation(inv);
202
+ if ((spec instanceof Date) && (isValidDate(spec))) {
203
+ if (spec.getTime() >= Date.now()) {
204
+ inv = new Invocation(self, spec);
205
+ scheduleInvocation(inv);
206
+ success = self.trackInvocation(inv);
207
+ }
168
208
  } else if (type === 'object') {
169
209
  if (!(spec instanceof RecurrenceRule)) {
170
210
  var r = new RecurrenceRule();
@@ -278,19 +318,16 @@ function RecurrenceRule(year, month, date, dayOfWeek, hour, minute, second) {
278
318
 
279
319
  RecurrenceRule.prototype.nextInvocationDate = function(base) {
280
320
  base = (base instanceof Date) ? base : (new Date());
281
- increment.addDateConvenienceMethods(base);
282
321
  if (!this.recurs) {
283
322
  return null;
284
323
  }
285
324
 
286
325
  var now = new Date();
287
- increment.addDateConvenienceMethods(now);
288
326
  if (this.year !== null && (typeof this.year == 'number') && this.year < now.getFullYear()) {
289
327
  return null;
290
328
  }
291
329
 
292
- var next = new Date(base.getTime());
293
- increment.addDateConvenienceMethods(next);
330
+ var next = new CronDate(base.getTime());
294
331
  next.addSecond();
295
332
 
296
333
  while (true) {
@@ -360,7 +397,7 @@ function runOnDate(date, job) {
360
397
  var then = date.getTime();
361
398
 
362
399
  if (then < now) {
363
- process.nextTick(job);
400
+ setImmediate(job);
364
401
  return null;
365
402
  }
366
403
 
@@ -471,6 +508,21 @@ function scheduleJob() {
471
508
  return null;
472
509
  }
473
510
 
511
+ function rescheduleJob(job, spec) {
512
+ if (job instanceof Job) {
513
+ if (job.reschedule(spec)) {
514
+ return job;
515
+ }
516
+ } else if (typeof job == 'string' || job instanceof String) {
517
+ if (job in scheduledJobs && scheduledJobs.hasOwnProperty(job)) {
518
+ if (scheduledJobs[job].reschedule(spec)) {
519
+ return scheduledJobs[job];
520
+ }
521
+ }
522
+ }
523
+ return null;
524
+ }
525
+
474
526
  function cancelJob(job) {
475
527
  var success = false;
476
528
  if (job instanceof Job) {
@@ -490,6 +542,6 @@ module.exports.Range = Range;
490
542
  module.exports.RecurrenceRule = RecurrenceRule;
491
543
  module.exports.Invocation = Invocation;
492
544
  module.exports.scheduleJob = scheduleJob;
545
+ module.exports.rescheduleJob = rescheduleJob;
493
546
  module.exports.scheduledJobs = scheduledJobs;
494
547
  module.exports.cancelJob = cancelJob;
495
- module.exports.addDateConvenienceMethods = increment.addDateConvenienceMethods;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-schedule",
3
- "version": "0.5.0",
3
+ "version": "1.1.0",
4
4
  "description": "A cron-like and not-cron-like job scheduler for Node.",
5
5
  "keywords": [
6
6
  "schedule",
@@ -23,7 +23,7 @@
23
23
  "url": "https://github.com/node-schedule/node-schedule.git"
24
24
  },
25
25
  "dependencies": {
26
- "cron-parser": "0.6.2",
26
+ "cron-parser": "1.1.0",
27
27
  "long-timeout": "0.0.2"
28
28
  },
29
29
  "devDependencies": {
@@ -48,17 +48,21 @@ module.exports = {
48
48
  }, 1250);
49
49
 
50
50
  clock.tick(1250);
51
- }
52
- /*,
53
- "Won't run job if scheduled in the past": function(test) {
54
- schedule.scheduleJob(new Date(Date.now() - 3000), function() {
51
+ },
52
+ "Won't run job if scheduled in the past": function(test) {
53
+ test.expect(1);
54
+ var job = schedule.scheduleJob(new Date(Date.now() - 3000), function() {
55
55
  test.ok(false);
56
- });
56
+ });
57
+
58
+ test.equal(job, null);
57
59
 
58
- setTimeout(function() {
60
+ setTimeout(function() {
59
61
  test.done();
60
- }, 1000);
61
- }*/
62
+ }, 1000);
63
+
64
+ clock.tick(1000);
65
+ }
62
66
  },
63
67
  ".scheduleJob(RecurrenceRule, fn)": {
64
68
  "Runs job at interval based on recur rule, repeating indefinitely": function(test) {
@@ -99,21 +103,24 @@ module.exports = {
99
103
  }, 3250);
100
104
 
101
105
  clock.tick(3250);
102
- }
103
- /*,
104
- "Doesn't invoke job if recur rule schedules it in the past": function(test) {
105
- var rule = new schedule.RecurrenceRule();
106
- rule.year = 2000;
106
+ },
107
+ "Doesn't invoke job if recur rule schedules it in the past": function(test) {
108
+ test.expect(1);
109
+ var rule = new schedule.RecurrenceRule();
110
+ rule.year = 1960;
107
111
 
108
- var job = schedule.scheduleJob(rule, function() {
112
+ var job = schedule.scheduleJob(rule, function() {
109
113
  test.ok(false);
110
- });
114
+ });
115
+
116
+ test.equal(job, null);
111
117
 
112
- setTimeout(function() {
113
- job.cancel();
118
+ setTimeout(function() {
114
119
  test.done();
115
- }, 1000);
116
- }*/
120
+ }, 1000);
121
+
122
+ clock.tick(1000);
123
+ }
117
124
  },
118
125
  ".scheduleJob({...}, fn)": {
119
126
  "Runs job at interval based on object, repeating indefinitely": function(test) {
@@ -155,20 +162,24 @@ module.exports = {
155
162
  }, 2250);
156
163
 
157
164
  clock.tick(2250);
158
- }
159
- /*,
160
- "Doesn't invoke job if object schedules it in the past": function(test) {
161
- var job = new schedule.scheduleJob({
162
- year: 2000
163
- }, function() {
165
+ },
166
+ "Doesn't invoke job if object schedules it in the past": function(test) {
167
+ test.expect(1);
168
+
169
+ var job = schedule.scheduleJob({
170
+ year: 1960
171
+ }, function() {
164
172
  test.ok(false);
165
- });
173
+ });
174
+
175
+ test.equal(job, null);
166
176
 
167
- setTimeout(function() {
168
- job.cancel();
177
+ setTimeout(function() {
169
178
  test.done();
170
- }, 1000);
171
- }*/
179
+ }, 1000);
180
+
181
+ clock.tick(1000);
182
+ }
172
183
  },
173
184
  ".scheduleJob({...}, {...}, fn)": {
174
185
  "Callback called for each job if callback is provided": function(test) {
@@ -188,6 +199,362 @@ module.exports = {
188
199
  clock.tick(3250);
189
200
  }
190
201
  },
202
+ ".rescheduleJob(job, {...})": {
203
+ "Reschedule jobs from object based to object based": function(test) {
204
+ test.expect(3);
205
+
206
+ var job = new schedule.scheduleJob({
207
+ second: null
208
+ }, function() {
209
+ test.ok(true);
210
+ });
211
+
212
+ setTimeout(function() {
213
+ schedule.rescheduleJob(job, {
214
+ minute: null
215
+ });
216
+ }, 3250);
217
+
218
+ setTimeout(function() {
219
+ job.cancel();
220
+ test.done();
221
+ }, 5000);
222
+
223
+ clock.tick(5000);
224
+ },
225
+ "Reschedule jobs from every minutes to every second": function(test) {
226
+ test.expect(3);
227
+
228
+ var timeout = 60 * 1000;
229
+
230
+ var job = new schedule.scheduleJob({
231
+ minute: null
232
+ }, function() {
233
+ test.ok(true);
234
+ });
235
+
236
+ setTimeout(function() {
237
+ schedule.rescheduleJob(job, {
238
+ second: null
239
+ });
240
+ }, timeout);
241
+
242
+ setTimeout(function() {
243
+ job.cancel();
244
+ test.done();
245
+ }, timeout + 2250);
246
+
247
+ clock.tick(timeout + 2250);
248
+ }
249
+ },
250
+ ".rescheduleJob(job, Date)": {
251
+ "Reschedule jobs from Date to Date": function(test) {
252
+ test.expect(1);
253
+
254
+ var job = new schedule.scheduleJob(new Date(Date.now() + 3000), function() {
255
+ test.ok(true);
256
+ });
257
+
258
+ setTimeout(function() {
259
+ schedule.rescheduleJob(job, new Date(Date.now() + 5000));
260
+ }, 1000);
261
+
262
+ setTimeout(function() {
263
+ test.done();
264
+ }, 6150);
265
+
266
+ clock.tick(6150);
267
+ },
268
+ "Reschedule jobs that has been executed": function(test) {
269
+ test.expect(2);
270
+
271
+ var job = new schedule.scheduleJob(new Date(Date.now() + 1000), function() {
272
+ test.ok(true);
273
+ });
274
+
275
+ setTimeout(function() {
276
+ schedule.rescheduleJob(job, new Date(Date.now() + 2000));
277
+ }, 2000);
278
+
279
+ setTimeout(function() {
280
+ test.done();
281
+ }, 5150);
282
+
283
+ clock.tick(5150);
284
+ }
285
+ },
286
+ ".rescheduleJob(job, RecurrenceRule)": {
287
+ "Reschedule jobs from RecurrenceRule to RecurrenceRule": function(test) {
288
+ test.expect(3);
289
+
290
+ var timeout = 60 * 1000;
291
+
292
+ var rule = new schedule.RecurrenceRule();
293
+ rule.second = null; // fire every second
294
+
295
+ var job = schedule.scheduleJob(rule, function() {
296
+ test.ok(true);
297
+ });
298
+
299
+ var newRule = new schedule.RecurrenceRule();
300
+ newRule.minute = null;
301
+
302
+ setTimeout(function() {
303
+ schedule.rescheduleJob(job, newRule);
304
+ }, 2250);
305
+
306
+ setTimeout(function() {
307
+ job.cancel();
308
+ test.done();
309
+ }, timeout + 2250);
310
+
311
+ clock.tick(timeout + 2250);
312
+ },
313
+ "Reschedule jobs from RecurrenceRule to Date": function(test) {
314
+ test.expect(3);
315
+
316
+ var rule = new schedule.RecurrenceRule();
317
+ rule.second = null; // fire every second
318
+
319
+ var job = schedule.scheduleJob(rule, function() {
320
+ test.ok(true);
321
+ });
322
+
323
+ setTimeout(function() {
324
+ schedule.rescheduleJob(job, new Date(Date.now() + 2000));
325
+ }, 2150);
326
+
327
+ setTimeout(function() {
328
+ test.done();
329
+ }, 4250);
330
+
331
+ clock.tick(4250);
332
+ },
333
+ "Reschedule jobs from RecurrenceRule to {...}": function(test) {
334
+ test.expect(3);
335
+
336
+ var timeout = 60 * 1000;
337
+
338
+ var rule = new schedule.RecurrenceRule();
339
+ rule.second = null; // fire every second
340
+
341
+ var job = schedule.scheduleJob(rule, function() {
342
+ test.ok(true);
343
+ });
344
+
345
+ setTimeout(function() {
346
+ schedule.rescheduleJob(job, {
347
+ minute: null
348
+ });
349
+ }, 2150);
350
+
351
+ setTimeout(function() {
352
+ job.cancel();
353
+ test.done();
354
+ }, timeout + 2150);
355
+
356
+ clock.tick(timeout + 2150);
357
+ },
358
+ "Reschedule jobs that is not available": function(test) {
359
+ test.expect(4);
360
+
361
+ var rule = new schedule.RecurrenceRule();
362
+ rule.second = null; // fire every second
363
+
364
+ var job = schedule.scheduleJob(rule, function() {
365
+ test.ok(true);
366
+ });
367
+
368
+ setTimeout(function() {
369
+ schedule.rescheduleJob(null, new Date(Date.now() + 2000));
370
+ }, 2150);
371
+
372
+ setTimeout(function() {
373
+ job.cancel();
374
+ test.done();
375
+ }, 4250);
376
+
377
+ clock.tick(4250);
378
+ }
379
+ },
380
+ '.rescheduleJob("job name", {...})': {
381
+ "Reschedule jobs from object based to object based": function(test) {
382
+ test.expect(3);
383
+
384
+ var job = new schedule.scheduleJob({
385
+ second: null
386
+ }, function() {
387
+ test.ok(true);
388
+ });
389
+
390
+ setTimeout(function() {
391
+ schedule.rescheduleJob(job.name, {
392
+ minute: null
393
+ });
394
+ }, 3250);
395
+
396
+ setTimeout(function() {
397
+ job.cancel();
398
+ test.done();
399
+ }, 5000);
400
+
401
+ clock.tick(5000);
402
+ },
403
+ "Reschedule jobs from every minutes to every second": function(test) {
404
+ test.expect(3);
405
+
406
+ var timeout = 60 * 1000;
407
+
408
+ var job = new schedule.scheduleJob({
409
+ minute: null
410
+ }, function() {
411
+ test.ok(true);
412
+ });
413
+
414
+ setTimeout(function() {
415
+ schedule.rescheduleJob(job.name, {
416
+ second: null
417
+ });
418
+ }, timeout);
419
+
420
+ setTimeout(function() {
421
+ job.cancel();
422
+ test.done();
423
+ }, timeout + 2250);
424
+
425
+ clock.tick(timeout + 2250);
426
+ }
427
+ },
428
+ '.rescheduleJob("job name", Date)': {
429
+ "Reschedule jobs from Date to Date": function(test) {
430
+ test.expect(1);
431
+
432
+ var job = new schedule.scheduleJob(new Date(Date.now() + 3000), function() {
433
+ test.ok(true);
434
+ });
435
+
436
+ setTimeout(function() {
437
+ schedule.rescheduleJob(job.name, new Date(Date.now() + 5000));
438
+ }, 1000);
439
+
440
+ setTimeout(function() {
441
+ test.done();
442
+ }, 6150);
443
+
444
+ clock.tick(6150);
445
+ },
446
+ "Reschedule jobs that has been executed": function(test) {
447
+ test.expect(2);
448
+
449
+ var job = new schedule.scheduleJob(new Date(Date.now() + 1000), function() {
450
+ test.ok(true);
451
+ });
452
+
453
+ setTimeout(function() {
454
+ schedule.rescheduleJob(job.name, new Date(Date.now() + 2000));
455
+ }, 2000);
456
+
457
+ setTimeout(function() {
458
+ test.done();
459
+ }, 5150);
460
+
461
+ clock.tick(5150);
462
+ }
463
+ },
464
+ '.rescheduleJob("job name", RecurrenceRule)': {
465
+ "Reschedule jobs from RecurrenceRule to RecurrenceRule": function(test) {
466
+ test.expect(3);
467
+
468
+ var timeout = 60 * 1000;
469
+
470
+ var rule = new schedule.RecurrenceRule();
471
+ rule.second = null; // fire every second
472
+
473
+ var job = schedule.scheduleJob(rule, function() {
474
+ test.ok(true);
475
+ });
476
+
477
+ var newRule = new schedule.RecurrenceRule();
478
+ newRule.minute = null;
479
+
480
+ setTimeout(function() {
481
+ schedule.rescheduleJob(job.name, newRule);
482
+ }, 2250);
483
+
484
+ setTimeout(function() {
485
+ job.cancel();
486
+ test.done();
487
+ }, timeout + 2250);
488
+
489
+ clock.tick(timeout + 2250);
490
+ },
491
+ "Reschedule jobs from RecurrenceRule to Date": function(test) {
492
+ test.expect(3);
493
+
494
+ var rule = new schedule.RecurrenceRule();
495
+ rule.second = null; // fire every second
496
+
497
+ var job = schedule.scheduleJob(rule, function() {
498
+ test.ok(true);
499
+ });
500
+
501
+ setTimeout(function() {
502
+ schedule.rescheduleJob(job.name, new Date(Date.now() + 2000));
503
+ }, 2150);
504
+
505
+ setTimeout(function() {
506
+ test.done();
507
+ }, 4250);
508
+
509
+ clock.tick(4250);
510
+ },
511
+ "Reschedule jobs from RecurrenceRule to {...}": function(test) {
512
+ test.expect(3);
513
+
514
+ var timeout = 60 * 1000;
515
+
516
+ var rule = new schedule.RecurrenceRule();
517
+ rule.second = null; // fire every second
518
+
519
+ var job = schedule.scheduleJob(rule, function() {
520
+ test.ok(true);
521
+ });
522
+
523
+ setTimeout(function() {
524
+ schedule.rescheduleJob(job.name, {
525
+ minute: null
526
+ });
527
+ }, 2150);
528
+
529
+ setTimeout(function() {
530
+ job.cancel();
531
+ test.done();
532
+ }, timeout + 2150);
533
+
534
+ clock.tick(timeout + 2150);
535
+ },
536
+ "Reschedule jobs that is not available": function(test) {
537
+ test.expect(4);
538
+
539
+ var rule = new schedule.RecurrenceRule();
540
+ rule.second = null; // fire every second
541
+
542
+ var job = schedule.scheduleJob(rule, function() {
543
+ test.ok(true);
544
+ });
545
+
546
+ setTimeout(function() {
547
+ schedule.rescheduleJob("Blah", new Date(Date.now() + 2000));
548
+ }, 2150);
549
+
550
+ setTimeout(function() {
551
+ job.cancel();
552
+ test.done();
553
+ }, 4250);
554
+
555
+ clock.tick(4250);
556
+ }
557
+ },
191
558
  ".cancelJob(Job)": {
192
559
  "Prevents all future invocations of Job passed in": function(test) {
193
560
  test.expect(2);
@@ -12,27 +12,6 @@ module.exports = {
12
12
  clock = sinon.useFakeTimers();
13
13
  cb();
14
14
  },
15
- "Date Enhancements": {
16
- "Should Not add date convenience methods unless explicitly specified": function(test) {
17
- test.ok(typeof Date.addYear !== 'function');
18
- test.ok(typeof Date.addMonth !== 'function');
19
- test.ok(typeof Date.addDay !== 'function');
20
- test.ok(typeof Date.addHour !== 'function');
21
- test.ok(typeof Date.addMinute !== 'function');
22
- test.ok(typeof Date.addSecond !== 'function');
23
- test.done();
24
- },
25
- "Should add date convenience methods when explicitly specified": function(test) {
26
- schedule.addDateConvenienceMethods(Date);
27
- test.ok(typeof Date.addYear === 'function');
28
- test.ok(typeof Date.addMonth === 'function');
29
- test.ok(typeof Date.addDay === 'function');
30
- test.ok(typeof Date.addHour === 'function');
31
- test.ok(typeof Date.addMinute === 'function');
32
- test.ok(typeof Date.addSecond === 'function');
33
- test.done();
34
- }
35
- },
36
15
  "Date string": {
37
16
  "Should accept a valid date string": function(test) {
38
17
  test.expect(1);
@@ -46,6 +25,16 @@ module.exports = {
46
25
  }, 1250);
47
26
 
48
27
  clock.tick(1250);
28
+ },
29
+ "Should not accept invalid string as valid date": function(test) {
30
+ test.expect(1);
31
+
32
+ var job = schedule.scheduleJob("hello!!", function() {
33
+ });
34
+
35
+ test.equal(job, null);
36
+ test.done();
37
+
49
38
  }
50
39
  },
51
40
  "UTC": {
@@ -12,6 +12,19 @@ module.exports = function(schedule) {
12
12
 
13
13
  job.runOnDate(new Date(Date.now() + 3000));
14
14
 
15
+ setTimeout(function() {
16
+ test.done();
17
+ }, 3250);
18
+ },
19
+ jobContextInGenerator: function(test) {
20
+ test.expect(1);
21
+
22
+ var job = new schedule.Job('name of job', function*() {
23
+ test.ok(this.name === 'name of job');
24
+ });
25
+
26
+ job.runOnDate(new Date(Date.now() + 3000));
27
+
15
28
  setTimeout(function() {
16
29
  test.done();
17
30
  }, 3250);
package/test/job-test.js CHANGED
@@ -97,38 +97,54 @@ module.exports = {
97
97
 
98
98
  clock.tick(3250);
99
99
  },
100
- /* No jobs will run after this test for some reason - hide for now
100
+ "Context is passed into generator correctly": function(test) {
101
+ if (!es6) {
102
+ test.expect(0);
103
+ test.done();
104
+ return;
105
+ }
106
+
107
+ es6.jobContextInGenerator(test);
108
+
109
+ clock.tick(3250);
110
+ },
101
111
  "Won't run job if scheduled in the past": function(test) {
102
112
  test.expect(0);
103
113
 
104
114
  var job = new schedule.Job(function() {
105
- test.ok(true);
115
+ test.ok(false);
106
116
  });
107
117
 
108
118
  job.schedule(new Date(Date.now() - 3000));
109
119
 
110
120
  setTimeout(function() {
111
- test.done();
121
+ test.done();
112
122
  }, 1000);
123
+
124
+ clock.tick(1000);
113
125
  },
114
126
  "Jobs still run after scheduling a Job in the past": function(test) {
115
127
  test.expect(1);
116
128
 
117
129
  var pastJob = new schedule.Job(function() {
118
130
  // Should not run, blow up if it does
119
- test.ok(false);
131
+ test.ok(false);
120
132
  });
133
+
121
134
  pastJob.schedule(new Date(Date.now() - 3000));
122
135
 
123
136
  var job = new schedule.Job(function() {
124
- test.ok(true);
137
+ test.ok(true);
125
138
  });
139
+
126
140
  job.schedule(new Date(Date.now() + 3000));
127
141
 
128
142
  setTimeout(function() {
129
- test.done();
143
+ test.done();
130
144
  }, 3250);
131
- },*/
145
+
146
+ clock.tick(3250);
147
+ },
132
148
  "Job emits 'scheduled' event with 'run at' Date": function(test) {
133
149
  test.expect(1);
134
150
 
@@ -204,25 +220,26 @@ module.exports = {
204
220
  }, 3250);
205
221
 
206
222
  clock.tick(3250);
207
- }
208
- /*,
209
- "Doesn't invoke job if recur rule schedules it in the past": function(test) {
210
- test.expect(0);
223
+ },
224
+ "Doesn't invoke job if recur rule schedules it in the past": function(test) {
225
+ test.expect(0);
211
226
 
212
- var job = new schedule.Job(function() {
227
+ var job = new schedule.Job(function() {
213
228
  test.ok(false);
214
- });
229
+ });
215
230
 
216
- var rule = new schedule.RecurrenceRule();
217
- rule.year = 2000;
231
+ var rule = new schedule.RecurrenceRule();
232
+ rule.year = 2000;
218
233
 
219
- job.schedule(rule);
234
+ job.schedule(rule);
220
235
 
221
- setTimeout(function() {
236
+ setTimeout(function() {
222
237
  job.cancel();
223
238
  test.done();
224
- }, 1000);
225
- }*/
239
+ }, 1000);
240
+
241
+ clock.tick(1000);
242
+ }
226
243
  },
227
244
  "#schedule({...})": {
228
245
  "Runs job at interval based on object, repeating indefinitely": function(test) {
@@ -264,24 +281,25 @@ module.exports = {
264
281
  }, 3250);
265
282
 
266
283
  clock.tick(3250);
267
- }
268
- /*,
269
- "Doesn't invoke job if object schedules it in the past": function(test) {
270
- test.expect(0);
284
+ },
285
+ "Doesn't invoke job if object schedules it in the past": function(test) {
286
+ test.expect(0);
271
287
 
272
- var job = new schedule.Job(function() {
288
+ var job = new schedule.Job(function() {
273
289
  test.ok(false);
274
- });
290
+ });
275
291
 
276
- job.schedule({
292
+ job.schedule({
277
293
  year: 2000
278
- });
294
+ });
279
295
 
280
- setTimeout(function() {
296
+ setTimeout(function() {
281
297
  job.cancel();
282
298
  test.done();
283
- }, 1000);
284
- }*/
299
+ }, 1000);
300
+
301
+ clock.tick(1000);
302
+ }
285
303
  },
286
304
  "#schedule('jobName', {...})": {
287
305
  "Runs job with a custom name input": function(test) {
@@ -399,19 +417,42 @@ module.exports = {
399
417
  function() {},
400
418
  function() {});
401
419
 
402
- test.equal(schedule.scheduledJobs.cancelJob, job1);
403
- test.equal(schedule.scheduledJobs.second, job2);
420
+ test.strictEqual(schedule.scheduledJobs.cancelJob, job1);
421
+ test.strictEqual(schedule.scheduledJobs.second, job2);
404
422
  setTimeout(function() {
405
423
  job1.cancel();
406
424
  job2.cancel();
407
- test.equal(schedule.scheduledJobs.cancelJob, null);
408
- test.equal(schedule.scheduledJobs.second, null);
425
+ test.strictEqual(schedule.scheduledJobs.cancelJob, undefined);
426
+ test.strictEqual(schedule.scheduledJobs.second, undefined);
409
427
  test.done();
410
428
  }, 1250);
411
429
 
412
430
  clock.tick(1250);
413
431
  }
414
432
  },
433
+ "#reschedule": {
434
+ "When rescheduled counter will be reset to zero": function(test) {
435
+
436
+ var job = new schedule.scheduleJob({
437
+ second: null
438
+ }, function() {});
439
+
440
+ setTimeout(function() {
441
+ test.equal(job.triggeredJobs(), 3);
442
+ schedule.rescheduleJob(job, {
443
+ minute: null
444
+ });
445
+ }, 3250);
446
+
447
+ setTimeout(function() {
448
+ job.cancel();
449
+ test.equal(job.triggeredJobs(), 0);
450
+ test.done();
451
+ }, 5000);
452
+
453
+ clock.tick(5000);
454
+ }
455
+ },
415
456
  "When invoked": {
416
457
  "Job emits 'run' event": function(test) {
417
458
  test.expect(1);
@@ -429,6 +470,21 @@ module.exports = {
429
470
  }, 3250);
430
471
 
431
472
  clock.tick(3250);
473
+ },
474
+ "Job counter increase properly": function(test) {
475
+ var job = new schedule.Job(function() {});
476
+
477
+ job.schedule({
478
+ second: null // fire every second
479
+ });
480
+
481
+ setTimeout(function() {
482
+ job.cancel();
483
+ test.equal(job.triggeredJobs(), 2);
484
+ test.done();
485
+ }, 2250);
486
+
487
+ clock.tick(2250);
432
488
  }
433
489
  },
434
490
  tearDown: function(cb) {
@@ -18,7 +18,7 @@ module.exports = {
18
18
  "Runs job every second": function(test) {
19
19
  test.expect(3);
20
20
 
21
- var timeout = 3 * 1000;
21
+ var timeout = 3 * 1000 + 150;
22
22
 
23
23
  var job = schedule.scheduleJob('* * * * * *', function() {
24
24
  test.ok(true);
package/lib/increment.js DELETED
@@ -1,40 +0,0 @@
1
-
2
- 'use strict';
3
-
4
- /*
5
- node-schedule
6
- A cron-like and not-cron-like job scheduler for Node.
7
-
8
- This file adds convenience functions for performing incremental date math
9
- in the Gregorian calendar.
10
- */
11
-
12
- module.exports.addDateConvenienceMethods = addDateConvenienceMethods;
13
-
14
- function addDateConvenienceMethods(Date) {
15
- if (typeof Date.addYear !== 'function') {
16
- Date.addYear = function() {
17
- this.setFullYear(this.getFullYear() + 1);
18
- };
19
-
20
- Date.addMonth = function() {
21
- this.setMonth(this.getMonth() + 1);
22
- };
23
-
24
- Date.addDay = function() {
25
- this.setDate(this.getDate() + 1);
26
- };
27
-
28
- Date.addHour = function() {
29
- this.setTime(this.getTime() + (60 * 60 * 1000));
30
- };
31
-
32
- Date.addMinute = function() {
33
- this.setTime(this.getTime() + (60 * 1000));
34
- };
35
-
36
- Date.addSecond = function() {
37
- this.setTime(this.getTime() + 1000);
38
- };
39
- }
40
- }