|
| 1 | +import MockDate from "mockdate"; |
1 | 2 | import { CronDaemon } from "../CronDaemon";
|
2 | 3 |
|
3 |
| -const waitFor = (ms: number) => |
4 |
| - new Promise((resolve, reject) => { |
5 |
| - setTimeout(resolve, ms); |
6 |
| - }); |
| 4 | +let daemon: CronDaemon | undefined; |
| 5 | + |
| 6 | +beforeAll(() => { |
| 7 | + MockDate.set(Date.now()); |
| 8 | +}); |
| 9 | +afterEach(() => { |
| 10 | + if (daemon) { |
| 11 | + daemon.stop(); |
| 12 | + daemon = undefined; |
| 13 | + } |
| 14 | +}); |
| 15 | +afterAll(() => { |
| 16 | + MockDate.reset(); |
| 17 | +}); |
7 | 18 |
|
8 | 19 | test("triggering", async () => {
|
9 | 20 | const callback = jest.fn();
|
10 |
| - const daemon = new CronDaemon("* * * * * * *", callback); |
| 21 | + daemon = new CronDaemon("* * * * * * *", callback); |
| 22 | + |
11 | 23 | expect(daemon.state()).toEqual("running");
|
12 | 24 | expect(callback).not.toHaveBeenCalled();
|
13 |
| - await waitFor(1000); |
| 25 | + |
| 26 | + MockDate.set(Date.now() + 1000); |
| 27 | + jest.advanceTimersByTime(1000); |
| 28 | + |
14 | 29 | expect(callback).toHaveBeenCalledTimes(1);
|
15 | 30 | });
|
16 | 31 |
|
17 | 32 | test("schedule without next date", async () => {
|
18 | 33 | const callback = jest.fn();
|
19 |
| - const daemon = new CronDaemon("* * * * * * 1980", callback); |
| 34 | + daemon = new CronDaemon("* * * * * * 1980", callback); |
| 35 | + |
20 | 36 | expect(daemon.next()).toBeUndefined();
|
21 |
| - await waitFor(1000); |
| 37 | + |
| 38 | + MockDate.set(Date.now() + 1000); |
| 39 | + jest.advanceTimersByTime(1000); |
| 40 | + |
22 | 41 | expect(callback).not.toHaveBeenCalled();
|
23 | 42 | });
|
24 | 43 |
|
25 | 44 | test("calling start multiple times", async () => {
|
26 | 45 | const callback = jest.fn();
|
27 |
| - const daemon = new CronDaemon("* * * * * * *", callback); |
| 46 | + daemon = new CronDaemon("* * * * * * *", callback); |
| 47 | + |
28 | 48 | daemon.start();
|
29 | 49 | daemon.start();
|
| 50 | + |
30 | 51 | expect(daemon.state()).toEqual("running");
|
31 | 52 | expect(callback).not.toHaveBeenCalled();
|
32 |
| - await waitFor(1000); |
| 53 | + |
| 54 | + MockDate.set(Date.now() + 1000); |
| 55 | + jest.advanceTimersByTime(1000); |
| 56 | + |
33 | 57 | expect(callback).toHaveBeenCalledTimes(1);
|
34 | 58 | });
|
35 | 59 |
|
36 | 60 | test("stopping", async () => {
|
37 | 61 | const callback = jest.fn();
|
38 |
| - const daemon = new CronDaemon("* * * * * * *", callback); |
| 62 | + daemon = new CronDaemon("* * * * * * *", callback); |
| 63 | + |
39 | 64 | daemon.stop();
|
| 65 | + |
40 | 66 | expect(daemon.state()).toEqual("stopped");
|
41 |
| - await waitFor(1000); |
| 67 | + |
| 68 | + MockDate.set(Date.now() + 1000); |
| 69 | + jest.advanceTimersByTime(1000); |
| 70 | + |
42 | 71 | expect(callback).not.toHaveBeenCalled();
|
43 | 72 | });
|
44 | 73 |
|
45 | 74 | test("doesn't break when next trigger is a long way away", async () => {
|
46 | 75 | const callback = jest.fn();
|
47 |
| - const daemon = new CronDaemon("* * * * * * 2099", callback); |
| 76 | + daemon = new CronDaemon("* * * * * * 2099", callback); |
| 77 | + |
48 | 78 | expect(daemon.state()).toEqual("running");
|
49 |
| - await waitFor(50); |
| 79 | + |
| 80 | + MockDate.set(Date.now() + 50); |
| 81 | + jest.advanceTimersByTime(50); |
| 82 | + |
50 | 83 | expect(callback).not.toHaveBeenCalled();
|
51 | 84 | });
|
52 | 85 |
|
53 | 86 | test("can call stop multiple times", async () => {
|
54 | 87 | const callback = jest.fn();
|
55 |
| - const daemon = new CronDaemon("* * * * * * *", callback); |
| 88 | + daemon = new CronDaemon("* * * * * * *", callback); |
| 89 | + |
56 | 90 | daemon.stop();
|
57 | 91 | daemon.stop();
|
| 92 | + |
58 | 93 | expect(daemon.state()).toEqual("stopped");
|
59 | 94 | expect(callback).not.toHaveBeenCalled();
|
60 | 95 | });
|
61 | 96 |
|
62 | 97 | test("custom date function", async () => {
|
63 | 98 | const callback = jest.fn();
|
64 |
| - const daemon = new CronDaemon((now) => { |
| 99 | + daemon = new CronDaemon((now) => { |
65 | 100 | const next = new Date(now);
|
66 | 101 | next.setTime(now.getTime() + 10);
|
67 | 102 | return next;
|
68 | 103 | }, callback);
|
69 |
| - await waitFor(20); |
| 104 | + |
| 105 | + MockDate.set(Date.now() + 50); |
| 106 | + jest.advanceTimersByTime(20); |
| 107 | + |
70 | 108 | expect(callback).toHaveBeenCalled();
|
71 | 109 | });
|
72 | 110 |
|
73 | 111 | test("Invalid schedule type causes an error", () => {
|
| 112 | + const callback = jest.fn(); |
74 | 113 | try {
|
75 |
| - new CronDaemon({} as any, jest.fn()); |
| 114 | + daemon = new CronDaemon({} as any, callback); |
76 | 115 | throw new Error("Should have failed validation");
|
77 | 116 | } catch (error) {
|
78 | 117 | expect(error.message).toEqual("Invalid schedule type");
|
| 118 | + expect(callback).not.toHaveBeenCalled(); |
79 | 119 | }
|
80 | 120 | });
|
| 121 | + |
| 122 | +test("Very long delay", () => { |
| 123 | + const maxDelay = Math.pow(2, 32 - 1) - 1; |
| 124 | + const requestedDelay = maxDelay * 1.5; |
| 125 | + const start = Date.now(); |
| 126 | + MockDate.set(start); |
| 127 | + |
| 128 | + const callback = jest.fn(); |
| 129 | + daemon = new CronDaemon( |
| 130 | + (now) => new Date(now.getTime() + requestedDelay), |
| 131 | + callback |
| 132 | + ); |
| 133 | + |
| 134 | + jest.runOnlyPendingTimers(); |
| 135 | + MockDate.set(start + maxDelay); |
| 136 | + |
| 137 | + expect(callback).not.toHaveBeenCalled(); |
| 138 | + |
| 139 | + MockDate.set(start + requestedDelay); |
| 140 | + jest.runOnlyPendingTimers(); |
| 141 | + |
| 142 | + expect(callback).toHaveBeenCalledTimes(1); |
| 143 | +}); |
0 commit comments