jcc-express-mvc 1.8.27 → 1.8.28
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/__tests__/ApplicationBuilder.test.js +3 -4
- package/__tests__/Job.test.js +5 -20
- package/__tests__/Schedule.test.d.ts +2 -0
- package/__tests__/Schedule.test.d.ts.map +1 -0
- package/__tests__/Schedule.test.js +580 -0
- package/__tests__/ValidationException.test.js +4 -3
- package/lib/Application/ApplicationBuilder.d.ts.map +1 -1
- package/lib/Application/ApplicationBuilder.js +0 -7
- package/lib/Auth/index.d.ts.map +1 -1
- package/lib/Auth/index.js +2 -1
- package/lib/Command-Line/MakeCommand.js +4 -1
- package/lib/Command-Line/ScheduleCommand.d.ts.map +1 -1
- package/lib/Command-Line/ScheduleCommand.js +8 -7
- package/lib/Command-Line/files/jobs.d.ts +1 -2
- package/lib/Command-Line/files/jobs.d.ts.map +1 -1
- package/lib/Command-Line/files/jobs.js +29 -21
- package/lib/Error/ValidationException-v2/index.d.ts.map +1 -1
- package/lib/Error/ValidationException-v2/index.js +6 -4
- package/lib/Queue/Drivers/MemoryDriver.d.ts.map +1 -1
- package/lib/Queue/Drivers/MemoryDriver.js +1 -1
- package/lib/Schedule/Schedule.d.ts +81 -89
- package/lib/Schedule/Schedule.d.ts.map +1 -1
- package/lib/Schedule/Schedule.js +167 -141
- package/lib/Schedule/Scheduler.d.ts +7 -34
- package/lib/Schedule/Scheduler.d.ts.map +1 -1
- package/lib/Schedule/Scheduler.js +156 -150
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +20 -5
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ const ApplicationBuilder_1 = require("../lib/Application/ApplicationBuilder");
|
|
|
15
15
|
(0, vitest_1.expect)(app.config).toMatchObject({ custom: "value" });
|
|
16
16
|
(0, vitest_1.expect)(app.has("Queue")).toBe(false);
|
|
17
17
|
});
|
|
18
|
-
(0, vitest_1.it)("withConfig
|
|
18
|
+
(0, vitest_1.it)("withConfig stores queue config without registering Queue (QueueServiceProvider handles that)", () => {
|
|
19
19
|
const config = {
|
|
20
20
|
queue: {
|
|
21
21
|
default: "memory",
|
|
@@ -26,9 +26,8 @@ const ApplicationBuilder_1 = require("../lib/Application/ApplicationBuilder");
|
|
|
26
26
|
};
|
|
27
27
|
const builder = new ApplicationBuilder_1.ApplicationBuilder(app);
|
|
28
28
|
builder.withConfig(config);
|
|
29
|
-
(0, vitest_1.expect)(app.
|
|
30
|
-
|
|
31
|
-
(0, vitest_1.expect)(queue).toBeDefined();
|
|
29
|
+
(0, vitest_1.expect)(app.config.queue).toMatchObject(config.queue);
|
|
30
|
+
(0, vitest_1.expect)(app.has("Queue")).toBe(false);
|
|
32
31
|
});
|
|
33
32
|
(0, vitest_1.it)("withRouting maps route config with rootPath", () => {
|
|
34
33
|
const builder = new ApplicationBuilder_1.ApplicationBuilder(app);
|
package/__tests__/Job.test.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const vitest_1 = require("vitest");
|
|
4
4
|
const Job_1 = require("../lib/Queue/Job");
|
|
5
|
+
const Queue_1 = require("../lib/Queue/Queue");
|
|
5
6
|
const Application_1 = require("../lib/Application/Application");
|
|
6
|
-
const ApplicationBuilder_1 = require("../lib/Application/ApplicationBuilder");
|
|
7
7
|
const util_1 = require("../lib/util");
|
|
8
8
|
class TestJob extends Job_1.Job {
|
|
9
9
|
async handle() {
|
|
@@ -112,15 +112,8 @@ class NestedFolderJob extends Job_1.Job {
|
|
|
112
112
|
app = Application_1.Application.getInstance();
|
|
113
113
|
originalApp = globalThis.app;
|
|
114
114
|
globalThis.app = app;
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
default: "memory",
|
|
118
|
-
connections: {
|
|
119
|
-
memory: { driver: "memory", queue: "default" },
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
new ApplicationBuilder_1.ApplicationBuilder(app).withConfig(config);
|
|
115
|
+
const q = new Queue_1.Queue({ driver: "memory", queue: "default" });
|
|
116
|
+
app.instance("Queue", q);
|
|
124
117
|
});
|
|
125
118
|
(0, vitest_1.afterEach)(() => {
|
|
126
119
|
globalThis.app = originalApp;
|
|
@@ -145,16 +138,8 @@ class NestedFolderJob extends Job_1.Job {
|
|
|
145
138
|
app = Application_1.Application.getInstance();
|
|
146
139
|
originalApp = globalThis.app;
|
|
147
140
|
globalThis.app = app;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
default: "memory",
|
|
151
|
-
connections: {
|
|
152
|
-
memory: { driver: "memory", queue: "default" },
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
new ApplicationBuilder_1.ApplicationBuilder(app).withConfig(config);
|
|
157
|
-
queue = app.resolve("Queue");
|
|
141
|
+
queue = new Queue_1.Queue({ driver: "memory", queue: "default" });
|
|
142
|
+
app.instance("Queue", queue);
|
|
158
143
|
});
|
|
159
144
|
(0, vitest_1.afterEach)(() => {
|
|
160
145
|
globalThis.app = originalApp;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Schedule.test.d.ts","sourceRoot":"","sources":["../../jcc-express-mvc/__tests__/Schedule.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const Schedule_1 = require("../lib/Schedule/Schedule");
|
|
5
|
+
const Scheduler_1 = require("../lib/Schedule/Scheduler");
|
|
6
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
7
|
+
function task(schedule) {
|
|
8
|
+
return schedule.getTasks()[0];
|
|
9
|
+
}
|
|
10
|
+
function makeScheduler(schedule) {
|
|
11
|
+
return new Scheduler_1.Scheduler(schedule);
|
|
12
|
+
}
|
|
13
|
+
// ─── Schedule.call / .command / .artisan / .exec ────────────────────────────
|
|
14
|
+
(0, vitest_1.describe)("Schedule task registration", () => {
|
|
15
|
+
(0, vitest_1.it)("call() registers a callback task", () => {
|
|
16
|
+
const s = new Schedule_1.Schedule();
|
|
17
|
+
const cb = async () => { };
|
|
18
|
+
s.call(cb, "my-callback");
|
|
19
|
+
(0, vitest_1.expect)(task(s).callback).toBe(cb);
|
|
20
|
+
(0, vitest_1.expect)(task(s).description).toBe("my-callback");
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)("command() prepends 'bun artisanNode'", () => {
|
|
23
|
+
const s = new Schedule_1.Schedule();
|
|
24
|
+
s.command("migrate", ["--fresh"]);
|
|
25
|
+
const cmd = task(s).command;
|
|
26
|
+
(0, vitest_1.expect)(cmd[0]).toBe("bun artisanNode migrate");
|
|
27
|
+
(0, vitest_1.expect)(cmd[1]).toEqual(["--fresh"]);
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)("artisan() does NOT double-prefix artisanNode", () => {
|
|
30
|
+
const s = new Schedule_1.Schedule();
|
|
31
|
+
s.artisan("queue:work");
|
|
32
|
+
const cmd = task(s).command;
|
|
33
|
+
// must be "bun artisanNode queue:work", not "bun artisanNode artisanNode queue:work"
|
|
34
|
+
(0, vitest_1.expect)(cmd[0]).toBe("bun artisanNode queue:work");
|
|
35
|
+
(0, vitest_1.expect)(cmd[0]).not.toContain("artisanNode artisanNode");
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)("exec() stores raw command without artisanNode prefix", () => {
|
|
38
|
+
const s = new Schedule_1.Schedule();
|
|
39
|
+
s.exec("node scripts/backup.js");
|
|
40
|
+
(0, vitest_1.expect)(task(s).command).toBe("node scripts/backup.js");
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.it)("exec() with args stores [cmd, args]", () => {
|
|
43
|
+
const s = new Schedule_1.Schedule();
|
|
44
|
+
s.exec("node", ["scripts/backup.js", "--force"]);
|
|
45
|
+
const cmd = task(s).command;
|
|
46
|
+
(0, vitest_1.expect)(cmd[0]).toBe("node");
|
|
47
|
+
(0, vitest_1.expect)(cmd[1]).toEqual(["scripts/backup.js", "--force"]);
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)("hasSubMinuteTasks() returns false when no sub-minute tasks", () => {
|
|
50
|
+
const s = new Schedule_1.Schedule();
|
|
51
|
+
s.call(async () => { }).everyMinute();
|
|
52
|
+
(0, vitest_1.expect)(s.hasSubMinuteTasks()).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)("hasSubMinuteTasks() returns true when a sub-minute task is registered", () => {
|
|
55
|
+
const s = new Schedule_1.Schedule();
|
|
56
|
+
s.call(async () => { }).everySecond();
|
|
57
|
+
(0, vitest_1.expect)(s.hasSubMinuteTasks()).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
// ─── Sub-minute ──────────────────────────────────────────────────────────────
|
|
61
|
+
(0, vitest_1.describe)("Sub-minute frequencies", () => {
|
|
62
|
+
const cases = [
|
|
63
|
+
["everySecond", () => new Schedule_1.Schedule().call(async () => { }).everySecond(), 1],
|
|
64
|
+
["everyTwoSeconds", () => new Schedule_1.Schedule().call(async () => { }).everyTwoSeconds(), 2],
|
|
65
|
+
["everyFiveSeconds", () => new Schedule_1.Schedule().call(async () => { }).everyFiveSeconds(), 5],
|
|
66
|
+
["everyTenSeconds", () => new Schedule_1.Schedule().call(async () => { }).everyTenSeconds(), 10],
|
|
67
|
+
["everyFifteenSeconds", () => new Schedule_1.Schedule().call(async () => { }).everyFifteenSeconds(), 15],
|
|
68
|
+
["everyTwentySeconds", () => new Schedule_1.Schedule().call(async () => { }).everyTwentySeconds(), 20],
|
|
69
|
+
["everyThirtySeconds", () => new Schedule_1.Schedule().call(async () => { }).everyThirtySeconds(), 30],
|
|
70
|
+
];
|
|
71
|
+
for (const [name, build, seconds] of cases) {
|
|
72
|
+
(0, vitest_1.it)(`${name}() sets secondInterval = ${seconds}`, () => {
|
|
73
|
+
const s = new Schedule_1.Schedule();
|
|
74
|
+
s.call(async () => { })[name]();
|
|
75
|
+
(0, vitest_1.expect)(task(s).secondInterval).toBe(seconds);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
(0, vitest_1.it)("sub-minute task has no cron expression side-effects on secondInterval", () => {
|
|
79
|
+
const s = new Schedule_1.Schedule();
|
|
80
|
+
s.call(async () => { }).everyFiveSeconds();
|
|
81
|
+
// expression still defaults to every-minute; secondInterval drives the check
|
|
82
|
+
(0, vitest_1.expect)(task(s).secondInterval).toBe(5);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
// ─── Minute frequencies ──────────────────────────────────────────────────────
|
|
86
|
+
(0, vitest_1.describe)("Minute frequencies", () => {
|
|
87
|
+
(0, vitest_1.it)("everyMinute() → '* * * * *'", () => {
|
|
88
|
+
const s = new Schedule_1.Schedule();
|
|
89
|
+
s.call(async () => { }).everyMinute();
|
|
90
|
+
(0, vitest_1.expect)(task(s).expression).toBe("* * * * *");
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)("everyTwoMinutes() → '*/2 * * * *'", () => {
|
|
93
|
+
const s = new Schedule_1.Schedule();
|
|
94
|
+
s.call(async () => { }).everyTwoMinutes();
|
|
95
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/2 * * * *");
|
|
96
|
+
});
|
|
97
|
+
(0, vitest_1.it)("everyThreeMinutes() → '*/3 * * * *'", () => {
|
|
98
|
+
const s = new Schedule_1.Schedule();
|
|
99
|
+
s.call(async () => { }).everyThreeMinutes();
|
|
100
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/3 * * * *");
|
|
101
|
+
});
|
|
102
|
+
(0, vitest_1.it)("everyFourMinutes() → '*/4 * * * *'", () => {
|
|
103
|
+
const s = new Schedule_1.Schedule();
|
|
104
|
+
s.call(async () => { }).everyFourMinutes();
|
|
105
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/4 * * * *");
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)("everyFiveMinutes() → '*/5 * * * *'", () => {
|
|
108
|
+
const s = new Schedule_1.Schedule();
|
|
109
|
+
s.call(async () => { }).everyFiveMinutes();
|
|
110
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/5 * * * *");
|
|
111
|
+
});
|
|
112
|
+
(0, vitest_1.it)("everyTenMinutes() → '*/10 * * * *'", () => {
|
|
113
|
+
const s = new Schedule_1.Schedule();
|
|
114
|
+
s.call(async () => { }).everyTenMinutes();
|
|
115
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/10 * * * *");
|
|
116
|
+
});
|
|
117
|
+
(0, vitest_1.it)("everyFifteenMinutes() → '*/15 * * * *'", () => {
|
|
118
|
+
const s = new Schedule_1.Schedule();
|
|
119
|
+
s.call(async () => { }).everyFifteenMinutes();
|
|
120
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/15 * * * *");
|
|
121
|
+
});
|
|
122
|
+
(0, vitest_1.it)("everyThirtyMinutes() → '*/30 * * * *'", () => {
|
|
123
|
+
const s = new Schedule_1.Schedule();
|
|
124
|
+
s.call(async () => { }).everyThirtyMinutes();
|
|
125
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/30 * * * *");
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)("everyMinutes(7) → '*/7 * * * *'", () => {
|
|
128
|
+
const s = new Schedule_1.Schedule();
|
|
129
|
+
s.call(async () => { }).everyMinutes(7);
|
|
130
|
+
(0, vitest_1.expect)(task(s).expression).toBe("*/7 * * * *");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
// ─── Hour frequencies ────────────────────────────────────────────────────────
|
|
134
|
+
(0, vitest_1.describe)("Hour frequencies", () => {
|
|
135
|
+
(0, vitest_1.it)("hourly() → '0 * * * *'", () => {
|
|
136
|
+
const s = new Schedule_1.Schedule();
|
|
137
|
+
s.call(async () => { }).hourly();
|
|
138
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 * * * *");
|
|
139
|
+
});
|
|
140
|
+
(0, vitest_1.it)("hourlyAt(17) → '17 * * * *'", () => {
|
|
141
|
+
const s = new Schedule_1.Schedule();
|
|
142
|
+
s.call(async () => { }).hourlyAt(17);
|
|
143
|
+
(0, vitest_1.expect)(task(s).expression).toBe("17 * * * *");
|
|
144
|
+
});
|
|
145
|
+
(0, vitest_1.it)("everyOddHour() → '0 1-23/2 * * *'", () => {
|
|
146
|
+
const s = new Schedule_1.Schedule();
|
|
147
|
+
s.call(async () => { }).everyOddHour();
|
|
148
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 1-23/2 * * *");
|
|
149
|
+
});
|
|
150
|
+
(0, vitest_1.it)("everyOddHour(30) → '30 1-23/2 * * *'", () => {
|
|
151
|
+
const s = new Schedule_1.Schedule();
|
|
152
|
+
s.call(async () => { }).everyOddHour(30);
|
|
153
|
+
(0, vitest_1.expect)(task(s).expression).toBe("30 1-23/2 * * *");
|
|
154
|
+
});
|
|
155
|
+
(0, vitest_1.it)("everyTwoHours() → '0 */2 * * *'", () => {
|
|
156
|
+
const s = new Schedule_1.Schedule();
|
|
157
|
+
s.call(async () => { }).everyTwoHours();
|
|
158
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 */2 * * *");
|
|
159
|
+
});
|
|
160
|
+
(0, vitest_1.it)("everyTwoHours(15) → '15 */2 * * *'", () => {
|
|
161
|
+
const s = new Schedule_1.Schedule();
|
|
162
|
+
s.call(async () => { }).everyTwoHours(15);
|
|
163
|
+
(0, vitest_1.expect)(task(s).expression).toBe("15 */2 * * *");
|
|
164
|
+
});
|
|
165
|
+
(0, vitest_1.it)("everyThreeHours() → '0 */3 * * *'", () => {
|
|
166
|
+
const s = new Schedule_1.Schedule();
|
|
167
|
+
s.call(async () => { }).everyThreeHours();
|
|
168
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 */3 * * *");
|
|
169
|
+
});
|
|
170
|
+
(0, vitest_1.it)("everyFourHours() → '0 */4 * * *'", () => {
|
|
171
|
+
const s = new Schedule_1.Schedule();
|
|
172
|
+
s.call(async () => { }).everyFourHours();
|
|
173
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 */4 * * *");
|
|
174
|
+
});
|
|
175
|
+
(0, vitest_1.it)("everySixHours() → '0 */6 * * *'", () => {
|
|
176
|
+
const s = new Schedule_1.Schedule();
|
|
177
|
+
s.call(async () => { }).everySixHours();
|
|
178
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 */6 * * *");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
// ─── Day frequencies ─────────────────────────────────────────────────────────
|
|
182
|
+
(0, vitest_1.describe)("Day frequencies", () => {
|
|
183
|
+
(0, vitest_1.it)("daily() → '0 0 * * *'", () => {
|
|
184
|
+
const s = new Schedule_1.Schedule();
|
|
185
|
+
s.call(async () => { }).daily();
|
|
186
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 * * *");
|
|
187
|
+
});
|
|
188
|
+
(0, vitest_1.it)("dailyAt('13:00') → '0 13 * * *'", () => {
|
|
189
|
+
const s = new Schedule_1.Schedule();
|
|
190
|
+
s.call(async () => { }).dailyAt("13:00");
|
|
191
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 13 * * *");
|
|
192
|
+
});
|
|
193
|
+
(0, vitest_1.it)("dailyAt('2:30') → '30 2 * * *'", () => {
|
|
194
|
+
const s = new Schedule_1.Schedule();
|
|
195
|
+
s.call(async () => { }).dailyAt("2:30");
|
|
196
|
+
(0, vitest_1.expect)(task(s).expression).toBe("30 2 * * *");
|
|
197
|
+
});
|
|
198
|
+
(0, vitest_1.it)("twiceDaily(1, 13) → '0 1,13 * * *'", () => {
|
|
199
|
+
const s = new Schedule_1.Schedule();
|
|
200
|
+
s.call(async () => { }).twiceDaily(1, 13);
|
|
201
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 1,13 * * *");
|
|
202
|
+
});
|
|
203
|
+
(0, vitest_1.it)("twiceDailyAt(1, 13, 15) → '15 1,13 * * *'", () => {
|
|
204
|
+
const s = new Schedule_1.Schedule();
|
|
205
|
+
s.call(async () => { }).twiceDailyAt(1, 13, 15);
|
|
206
|
+
(0, vitest_1.expect)(task(s).expression).toBe("15 1,13 * * *");
|
|
207
|
+
});
|
|
208
|
+
(0, vitest_1.it)("twiceDailyAt() with defaults → '0 1,13 * * *'", () => {
|
|
209
|
+
const s = new Schedule_1.Schedule();
|
|
210
|
+
s.call(async () => { }).twiceDailyAt();
|
|
211
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 1,13 * * *");
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
// ─── Day-of-month ────────────────────────────────────────────────────────────
|
|
215
|
+
(0, vitest_1.describe)("Day-of-month frequencies", () => {
|
|
216
|
+
(0, vitest_1.it)("daysOfMonth([1, 10, 20]) sets day-of-month field", () => {
|
|
217
|
+
const s = new Schedule_1.Schedule();
|
|
218
|
+
s.call(async () => { }).daily().daysOfMonth([1, 10, 20]);
|
|
219
|
+
const parts = task(s).expression.split(" ");
|
|
220
|
+
(0, vitest_1.expect)(parts[2]).toBe("1,10,20");
|
|
221
|
+
});
|
|
222
|
+
(0, vitest_1.it)("lastDayOfMonth() sets lastDayOfMonth flag", () => {
|
|
223
|
+
const s = new Schedule_1.Schedule();
|
|
224
|
+
s.call(async () => { }).lastDayOfMonth();
|
|
225
|
+
(0, vitest_1.expect)(task(s).lastDayOfMonth).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
(0, vitest_1.it)("lastDayOfMonth('15:00') sets the correct time in expression", () => {
|
|
228
|
+
const s = new Schedule_1.Schedule();
|
|
229
|
+
s.call(async () => { }).lastDayOfMonth("15:00");
|
|
230
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 15 * * *");
|
|
231
|
+
(0, vitest_1.expect)(task(s).lastDayOfMonth).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
// ─── Week frequencies ────────────────────────────────────────────────────────
|
|
235
|
+
(0, vitest_1.describe)("Week frequencies", () => {
|
|
236
|
+
(0, vitest_1.it)("weekly() → '0 0 * * 0'", () => {
|
|
237
|
+
const s = new Schedule_1.Schedule();
|
|
238
|
+
s.call(async () => { }).weekly();
|
|
239
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 * * 0");
|
|
240
|
+
});
|
|
241
|
+
(0, vitest_1.it)("weeklyOn(1, '8:00') → '0 8 * * 1'", () => {
|
|
242
|
+
const s = new Schedule_1.Schedule();
|
|
243
|
+
s.call(async () => { }).weeklyOn(1, "8:00");
|
|
244
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 8 * * 1");
|
|
245
|
+
});
|
|
246
|
+
(0, vitest_1.it)("weeklyOn(5) defaults to midnight → '0 0 * * 5'", () => {
|
|
247
|
+
const s = new Schedule_1.Schedule();
|
|
248
|
+
s.call(async () => { }).weeklyOn(5);
|
|
249
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 * * 5");
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
// ─── Month frequencies ───────────────────────────────────────────────────────
|
|
253
|
+
(0, vitest_1.describe)("Month frequencies", () => {
|
|
254
|
+
(0, vitest_1.it)("monthly() → '0 0 1 * *'", () => {
|
|
255
|
+
const s = new Schedule_1.Schedule();
|
|
256
|
+
s.call(async () => { }).monthly();
|
|
257
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 1 * *");
|
|
258
|
+
});
|
|
259
|
+
(0, vitest_1.it)("monthlyOn(4, '15:00') → '0 15 4 * *'", () => {
|
|
260
|
+
const s = new Schedule_1.Schedule();
|
|
261
|
+
s.call(async () => { }).monthlyOn(4, "15:00");
|
|
262
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 15 4 * *");
|
|
263
|
+
});
|
|
264
|
+
(0, vitest_1.it)("twiceMonthly(1, 16, '13:00') → '0 13 1,16 * *'", () => {
|
|
265
|
+
const s = new Schedule_1.Schedule();
|
|
266
|
+
s.call(async () => { }).twiceMonthly(1, 16, "13:00");
|
|
267
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 13 1,16 * *");
|
|
268
|
+
});
|
|
269
|
+
(0, vitest_1.it)("twiceMonthly() with defaults → '0 0 1,16 * *'", () => {
|
|
270
|
+
const s = new Schedule_1.Schedule();
|
|
271
|
+
s.call(async () => { }).twiceMonthly();
|
|
272
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 1,16 * *");
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
// ─── Quarter / Year frequencies ──────────────────────────────────────────────
|
|
276
|
+
(0, vitest_1.describe)("Quarter and year frequencies", () => {
|
|
277
|
+
(0, vitest_1.it)("quarterly() → '0 0 1 */3 *'", () => {
|
|
278
|
+
const s = new Schedule_1.Schedule();
|
|
279
|
+
s.call(async () => { }).quarterly();
|
|
280
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 1 */3 *");
|
|
281
|
+
});
|
|
282
|
+
(0, vitest_1.it)("quarterlyOn(4, '14:00') → '0 14 4 */3 *'", () => {
|
|
283
|
+
const s = new Schedule_1.Schedule();
|
|
284
|
+
s.call(async () => { }).quarterlyOn(4, "14:00");
|
|
285
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 14 4 */3 *");
|
|
286
|
+
});
|
|
287
|
+
(0, vitest_1.it)("yearly() → '0 0 1 1 *'", () => {
|
|
288
|
+
const s = new Schedule_1.Schedule();
|
|
289
|
+
s.call(async () => { }).yearly();
|
|
290
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 1 1 *");
|
|
291
|
+
});
|
|
292
|
+
(0, vitest_1.it)("yearlyOn(6, 1, '17:00') → '0 17 1 6 *'", () => {
|
|
293
|
+
const s = new Schedule_1.Schedule();
|
|
294
|
+
s.call(async () => { }).yearlyOn(6, 1, "17:00");
|
|
295
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 17 1 6 *");
|
|
296
|
+
});
|
|
297
|
+
(0, vitest_1.it)("yearlyOn() with defaults → '0 0 1 1 *'", () => {
|
|
298
|
+
const s = new Schedule_1.Schedule();
|
|
299
|
+
s.call(async () => { }).yearlyOn();
|
|
300
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 0 1 1 *");
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
// ─── Custom / cron ───────────────────────────────────────────────────────────
|
|
304
|
+
(0, vitest_1.describe)("Custom cron expression", () => {
|
|
305
|
+
(0, vitest_1.it)("cron() stores expression as-is", () => {
|
|
306
|
+
const s = new Schedule_1.Schedule();
|
|
307
|
+
s.call(async () => { }).cron("0 6,12,18 * * *");
|
|
308
|
+
(0, vitest_1.expect)(task(s).expression).toBe("0 6,12,18 * * *");
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
// ─── Day filters ─────────────────────────────────────────────────────────────
|
|
312
|
+
(0, vitest_1.describe)("Day filters", () => {
|
|
313
|
+
(0, vitest_1.it)("weekdays() sets day-of-week to 1-5", () => {
|
|
314
|
+
const s = new Schedule_1.Schedule();
|
|
315
|
+
s.call(async () => { }).daily().weekdays();
|
|
316
|
+
const parts = task(s).expression.split(" ");
|
|
317
|
+
(0, vitest_1.expect)(parts[4]).toBe("1-5");
|
|
318
|
+
});
|
|
319
|
+
(0, vitest_1.it)("weekends() sets day-of-week to 0,6", () => {
|
|
320
|
+
const s = new Schedule_1.Schedule();
|
|
321
|
+
s.call(async () => { }).daily().weekends();
|
|
322
|
+
const parts = task(s).expression.split(" ");
|
|
323
|
+
(0, vitest_1.expect)(parts[4]).toBe("0,6");
|
|
324
|
+
});
|
|
325
|
+
(0, vitest_1.it)("days([1,3,5]) sets day-of-week", () => {
|
|
326
|
+
const s = new Schedule_1.Schedule();
|
|
327
|
+
s.call(async () => { }).daily().days([1, 3, 5]);
|
|
328
|
+
const parts = task(s).expression.split(" ");
|
|
329
|
+
(0, vitest_1.expect)(parts[4]).toBe("1,3,5");
|
|
330
|
+
});
|
|
331
|
+
(0, vitest_1.it)("at('9:30') overrides hour and minute", () => {
|
|
332
|
+
const s = new Schedule_1.Schedule();
|
|
333
|
+
s.call(async () => { }).daily().at("9:30");
|
|
334
|
+
const parts = task(s).expression.split(" ");
|
|
335
|
+
(0, vitest_1.expect)(parts[0]).toBe("30"); // minute
|
|
336
|
+
(0, vitest_1.expect)(parts[1]).toBe("9"); // hour
|
|
337
|
+
});
|
|
338
|
+
(0, vitest_1.it)("between() stores betweenHours metadata", () => {
|
|
339
|
+
const s = new Schedule_1.Schedule();
|
|
340
|
+
s.call(async () => { }).hourly().between(8, 17);
|
|
341
|
+
(0, vitest_1.expect)(task(s).betweenHours).toEqual([8, 17]);
|
|
342
|
+
});
|
|
343
|
+
// ─── Named day shortcuts ────────────────────────────────────────────────────
|
|
344
|
+
const namedDays = [
|
|
345
|
+
["sundays", 0],
|
|
346
|
+
["mondays", 1],
|
|
347
|
+
["tuesdays", 2],
|
|
348
|
+
["wednesdays", 3],
|
|
349
|
+
["thursdays", 4],
|
|
350
|
+
["fridays", 5],
|
|
351
|
+
["saturdays", 6],
|
|
352
|
+
];
|
|
353
|
+
for (const [method, dayIndex] of namedDays) {
|
|
354
|
+
(0, vitest_1.it)(`${method}() sets day-of-week to ${dayIndex}`, () => {
|
|
355
|
+
const s = new Schedule_1.Schedule();
|
|
356
|
+
s.call(async () => { }).daily()[method]();
|
|
357
|
+
const parts = task(s).expression.split(" ");
|
|
358
|
+
(0, vitest_1.expect)(parts[4]).toBe(String(dayIndex));
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
// ─── unlessBetween ──────────────────────────────────────────────────────────
|
|
362
|
+
(0, vitest_1.it)("unlessBetween() stores unlessBetweenHours", () => {
|
|
363
|
+
const s = new Schedule_1.Schedule();
|
|
364
|
+
s.call(async () => { }).hourly().unlessBetween(23, 6);
|
|
365
|
+
(0, vitest_1.expect)(task(s).unlessBetweenHours).toEqual([23, 6]);
|
|
366
|
+
});
|
|
367
|
+
// ─── when ───────────────────────────────────────────────────────────────────
|
|
368
|
+
(0, vitest_1.it)("when() stores the predicate function", () => {
|
|
369
|
+
const s = new Schedule_1.Schedule();
|
|
370
|
+
const cond = () => true;
|
|
371
|
+
s.call(async () => { }).daily().when(cond);
|
|
372
|
+
(0, vitest_1.expect)(task(s).whenCondition).toBe(cond);
|
|
373
|
+
});
|
|
374
|
+
// ─── environments ────────────────────────────────────────────────────────────
|
|
375
|
+
(0, vitest_1.it)("environments() stores the environment list", () => {
|
|
376
|
+
const s = new Schedule_1.Schedule();
|
|
377
|
+
s.call(async () => { }).daily().environments("production", "staging");
|
|
378
|
+
(0, vitest_1.expect)(task(s).environments).toEqual(["production", "staging"]);
|
|
379
|
+
});
|
|
380
|
+
(0, vitest_1.it)("environments() accepts a single value", () => {
|
|
381
|
+
const s = new Schedule_1.Schedule();
|
|
382
|
+
s.call(async () => { }).daily().environments("production");
|
|
383
|
+
(0, vitest_1.expect)(task(s).environments).toEqual(["production"]);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
// ─── Options ─────────────────────────────────────────────────────────────────
|
|
387
|
+
(0, vitest_1.describe)("Task options", () => {
|
|
388
|
+
(0, vitest_1.it)("timezone() sets timezone", () => {
|
|
389
|
+
const s = new Schedule_1.Schedule();
|
|
390
|
+
s.call(async () => { }).daily().timezone("America/New_York");
|
|
391
|
+
(0, vitest_1.expect)(task(s).timezone).toBe("America/New_York");
|
|
392
|
+
});
|
|
393
|
+
(0, vitest_1.it)("withoutOverlapping() sets flag", () => {
|
|
394
|
+
const s = new Schedule_1.Schedule();
|
|
395
|
+
s.call(async () => { }).daily().withoutOverlapping();
|
|
396
|
+
(0, vitest_1.expect)(task(s).withoutOverlapping).toBe(true);
|
|
397
|
+
});
|
|
398
|
+
(0, vitest_1.it)("runInBackground() sets flag", () => {
|
|
399
|
+
const s = new Schedule_1.Schedule();
|
|
400
|
+
s.call(async () => { }).daily().runInBackground();
|
|
401
|
+
(0, vitest_1.expect)(task(s).runInBackground).toBe(true);
|
|
402
|
+
});
|
|
403
|
+
(0, vitest_1.it)("onOneServer() sets flag", () => {
|
|
404
|
+
const s = new Schedule_1.Schedule();
|
|
405
|
+
s.call(async () => { }).daily().onOneServer();
|
|
406
|
+
(0, vitest_1.expect)(task(s).onOneServer).toBe(true);
|
|
407
|
+
});
|
|
408
|
+
(0, vitest_1.it)("description() sets description", () => {
|
|
409
|
+
const s = new Schedule_1.Schedule();
|
|
410
|
+
s.call(async () => { }).daily().description("Nightly cleanup");
|
|
411
|
+
(0, vitest_1.expect)(task(s).description).toBe("Nightly cleanup");
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
// ─── Scheduler isDue — sub-minute ────────────────────────────────────────────
|
|
415
|
+
(0, vitest_1.describe)("Scheduler isDue — secondInterval", () => {
|
|
416
|
+
(0, vitest_1.it)("fires immediately when lastRunAt is undefined", async () => {
|
|
417
|
+
const s = new Schedule_1.Schedule();
|
|
418
|
+
let ran = false;
|
|
419
|
+
s.call(async () => { ran = true; }).everyTenSeconds();
|
|
420
|
+
const scheduler = makeScheduler(s);
|
|
421
|
+
await scheduler.run();
|
|
422
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
423
|
+
});
|
|
424
|
+
(0, vitest_1.it)("does not fire again before the interval has elapsed", async () => {
|
|
425
|
+
const s = new Schedule_1.Schedule();
|
|
426
|
+
let count = 0;
|
|
427
|
+
s.call(async () => { count++; }).everyTenSeconds();
|
|
428
|
+
const scheduler = makeScheduler(s);
|
|
429
|
+
await scheduler.run(); // first run → sets lastRunAt
|
|
430
|
+
await scheduler.run(); // second run immediately → not due
|
|
431
|
+
(0, vitest_1.expect)(count).toBe(1);
|
|
432
|
+
});
|
|
433
|
+
(0, vitest_1.it)("fires again after the interval has elapsed", async () => {
|
|
434
|
+
const s = new Schedule_1.Schedule();
|
|
435
|
+
let count = 0;
|
|
436
|
+
s.call(async () => { count++; }).everyTenSeconds();
|
|
437
|
+
const t = task(s);
|
|
438
|
+
const scheduler = makeScheduler(s);
|
|
439
|
+
await scheduler.run(); // first run
|
|
440
|
+
t.lastRunAt = Date.now() - 11_000; // backdate by 11 seconds
|
|
441
|
+
await scheduler.run(); // should fire again
|
|
442
|
+
(0, vitest_1.expect)(count).toBe(2);
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
// ─── Scheduler isDue — lastDayOfMonth ────────────────────────────────────────
|
|
446
|
+
(0, vitest_1.describe)("Scheduler isDue — lastDayOfMonth", () => {
|
|
447
|
+
(0, vitest_1.afterEach)(() => {
|
|
448
|
+
vitest_1.vi.useRealTimers();
|
|
449
|
+
});
|
|
450
|
+
(0, vitest_1.it)("runs when today is the last day of the month", async () => {
|
|
451
|
+
// Freeze time to Jan 31 at midnight
|
|
452
|
+
vitest_1.vi.useFakeTimers();
|
|
453
|
+
vitest_1.vi.setSystemTime(new Date("2024-01-31T00:00:00"));
|
|
454
|
+
const s = new Schedule_1.Schedule();
|
|
455
|
+
let ran = false;
|
|
456
|
+
s.call(async () => { ran = true; }).lastDayOfMonth();
|
|
457
|
+
const scheduler = makeScheduler(s);
|
|
458
|
+
await scheduler.run();
|
|
459
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
460
|
+
});
|
|
461
|
+
(0, vitest_1.it)("does not run when today is not the last day of the month", async () => {
|
|
462
|
+
vitest_1.vi.useFakeTimers();
|
|
463
|
+
vitest_1.vi.setSystemTime(new Date("2024-01-15T00:00:00"));
|
|
464
|
+
const s = new Schedule_1.Schedule();
|
|
465
|
+
let ran = false;
|
|
466
|
+
s.call(async () => { ran = true; }).lastDayOfMonth();
|
|
467
|
+
const scheduler = makeScheduler(s);
|
|
468
|
+
await scheduler.run();
|
|
469
|
+
(0, vitest_1.expect)(ran).toBe(false);
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
// ─── Scheduler — unlessBetween ───────────────────────────────────────────────
|
|
473
|
+
(0, vitest_1.describe)("Scheduler — unlessBetween", () => {
|
|
474
|
+
(0, vitest_1.afterEach)(() => vitest_1.vi.useRealTimers());
|
|
475
|
+
(0, vitest_1.it)("skips the task when current hour is inside the blocked window", async () => {
|
|
476
|
+
vitest_1.vi.useFakeTimers();
|
|
477
|
+
vitest_1.vi.setSystemTime(new Date("2024-01-15T02:00:00")); // 2am
|
|
478
|
+
const s = new Schedule_1.Schedule();
|
|
479
|
+
let ran = false;
|
|
480
|
+
s.call(async () => { ran = true; }).everyMinute().unlessBetween(23, 6);
|
|
481
|
+
await makeScheduler(s).run();
|
|
482
|
+
(0, vitest_1.expect)(ran).toBe(false);
|
|
483
|
+
});
|
|
484
|
+
(0, vitest_1.it)("runs the task when current hour is outside the blocked window", async () => {
|
|
485
|
+
vitest_1.vi.useFakeTimers();
|
|
486
|
+
vitest_1.vi.setSystemTime(new Date("2024-01-15T10:00:00")); // 10am
|
|
487
|
+
const s = new Schedule_1.Schedule();
|
|
488
|
+
let ran = false;
|
|
489
|
+
s.call(async () => { ran = true; }).everyMinute().unlessBetween(23, 6);
|
|
490
|
+
await makeScheduler(s).run();
|
|
491
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
// ─── Scheduler — when ────────────────────────────────────────────────────────
|
|
495
|
+
(0, vitest_1.describe)("Scheduler — when()", () => {
|
|
496
|
+
(0, vitest_1.it)("runs the task when the sync predicate returns true", async () => {
|
|
497
|
+
const s = new Schedule_1.Schedule();
|
|
498
|
+
let ran = false;
|
|
499
|
+
s.call(async () => { ran = true; }).everyMinute().when(() => true);
|
|
500
|
+
await makeScheduler(s).run();
|
|
501
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
502
|
+
});
|
|
503
|
+
(0, vitest_1.it)("skips the task when the sync predicate returns false", async () => {
|
|
504
|
+
const s = new Schedule_1.Schedule();
|
|
505
|
+
let ran = false;
|
|
506
|
+
s.call(async () => { ran = true; }).everyMinute().when(() => false);
|
|
507
|
+
await makeScheduler(s).run();
|
|
508
|
+
(0, vitest_1.expect)(ran).toBe(false);
|
|
509
|
+
});
|
|
510
|
+
(0, vitest_1.it)("supports an async predicate", async () => {
|
|
511
|
+
const s = new Schedule_1.Schedule();
|
|
512
|
+
let ran = false;
|
|
513
|
+
s.call(async () => { ran = true; })
|
|
514
|
+
.everyMinute()
|
|
515
|
+
.when(async () => Promise.resolve(true));
|
|
516
|
+
await makeScheduler(s).run();
|
|
517
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
518
|
+
});
|
|
519
|
+
(0, vitest_1.it)("skips when async predicate resolves false", async () => {
|
|
520
|
+
const s = new Schedule_1.Schedule();
|
|
521
|
+
let ran = false;
|
|
522
|
+
s.call(async () => { ran = true; })
|
|
523
|
+
.everyMinute()
|
|
524
|
+
.when(async () => Promise.resolve(false));
|
|
525
|
+
await makeScheduler(s).run();
|
|
526
|
+
(0, vitest_1.expect)(ran).toBe(false);
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
// ─── Scheduler — environments ─────────────────────────────────────────────────
|
|
530
|
+
(0, vitest_1.describe)("Scheduler — environments()", () => {
|
|
531
|
+
const originalAppEnv = process.env.APP_ENV;
|
|
532
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
533
|
+
(0, vitest_1.afterEach)(() => {
|
|
534
|
+
process.env.APP_ENV = originalAppEnv;
|
|
535
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
536
|
+
});
|
|
537
|
+
(0, vitest_1.it)("runs when APP_ENV matches", async () => {
|
|
538
|
+
process.env.APP_ENV = "production";
|
|
539
|
+
const s = new Schedule_1.Schedule();
|
|
540
|
+
let ran = false;
|
|
541
|
+
s.call(async () => { ran = true; }).everyMinute().environments("production");
|
|
542
|
+
await makeScheduler(s).run();
|
|
543
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
544
|
+
});
|
|
545
|
+
(0, vitest_1.it)("skips when APP_ENV does not match", async () => {
|
|
546
|
+
process.env.APP_ENV = "local";
|
|
547
|
+
const s = new Schedule_1.Schedule();
|
|
548
|
+
let ran = false;
|
|
549
|
+
s.call(async () => { ran = true; }).everyMinute().environments("production");
|
|
550
|
+
await makeScheduler(s).run();
|
|
551
|
+
(0, vitest_1.expect)(ran).toBe(false);
|
|
552
|
+
});
|
|
553
|
+
(0, vitest_1.it)("matches any of multiple environments", async () => {
|
|
554
|
+
process.env.APP_ENV = "staging";
|
|
555
|
+
const s = new Schedule_1.Schedule();
|
|
556
|
+
let ran = false;
|
|
557
|
+
s.call(async () => { ran = true; })
|
|
558
|
+
.everyMinute()
|
|
559
|
+
.environments("production", "staging");
|
|
560
|
+
await makeScheduler(s).run();
|
|
561
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
562
|
+
});
|
|
563
|
+
(0, vitest_1.it)("is case-insensitive", async () => {
|
|
564
|
+
process.env.APP_ENV = "Production";
|
|
565
|
+
const s = new Schedule_1.Schedule();
|
|
566
|
+
let ran = false;
|
|
567
|
+
s.call(async () => { ran = true; }).everyMinute().environments("production");
|
|
568
|
+
await makeScheduler(s).run();
|
|
569
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
570
|
+
});
|
|
571
|
+
(0, vitest_1.it)("falls back to NODE_ENV when APP_ENV is not set", async () => {
|
|
572
|
+
delete process.env.APP_ENV;
|
|
573
|
+
process.env.NODE_ENV = "test";
|
|
574
|
+
const s = new Schedule_1.Schedule();
|
|
575
|
+
let ran = false;
|
|
576
|
+
s.call(async () => { ran = true; }).everyMinute().environments("test");
|
|
577
|
+
await makeScheduler(s).run();
|
|
578
|
+
(0, vitest_1.expect)(ran).toBe(true);
|
|
579
|
+
});
|
|
580
|
+
});
|