Skip to content

Commit 5524ae1

Browse files
committed
chore: wip
1 parent f3e2dcd commit 5524ae1

File tree

3 files changed

+134
-118
lines changed

3 files changed

+134
-118
lines changed

storage/framework/core/scheduler/src/schedule.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ export class Schedule {
4242
return this
4343
}
4444

45+
everyHour() {
46+
this.cronPattern = '0 0 * * * *'
47+
return this
48+
}
49+
50+
everyDay() {
51+
this.cronPattern = '0 0 0 * * *'
52+
return this
53+
}
54+
4555
hourly() {
4656
this.cronPattern = '0 0 * * * *'
4757
return this
@@ -115,6 +125,8 @@ export class Schedule {
115125
}
116126
}
117127

128+
export class Job extends Schedule {}
129+
118130
export function sendAt(cronTime: string | Date | DateTime): DateTime {
119131
return new CronTime(cronTime).sendAt()
120132
}
Lines changed: 121 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,161 @@
1-
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test'
2-
import { DateTime } from 'luxon'
3-
import { CronJob, Schedule, sendAt, timeout } from '../src'
1+
import { beforeEach, describe, expect, it, mock } from 'bun:test'
2+
import { CronJob, CronTime, Job, Schedule, sendAt, timeout } from '../src'
3+
4+
// Mock log.info
5+
const mockLogInfo = mock(() => {})
6+
mock.module('@stacksjs/cli', () => ({
7+
log: { info: mockLogInfo },
8+
}))
49

510
describe('@stacksjs/scheduler', () => {
6-
let originalDateNow: () => number
11+
let schedule: Schedule
12+
let mockTask: () => void
713

814
beforeEach(() => {
9-
originalDateNow = Date.now
10-
Date.now = () => new Date('2024-01-01T00:00:00Z').getTime()
11-
})
12-
13-
afterEach(() => {
14-
Date.now = originalDateNow
15+
mockTask = mock(() => {})
16+
schedule = new Schedule(mockTask)
17+
mockLogInfo.mockClear()
1518
})
1619

17-
describe('Schedule class', () => {
18-
it('should create a schedule with everySecond', () => {
19-
const task = mock(() => {})
20-
const schedule = new Schedule(task).everySecond()
21-
expect((schedule as any).cronPattern).toBe('* * * * * *')
22-
})
23-
24-
it('should create a schedule with everyMinute', () => {
25-
const task = mock(() => {})
26-
const schedule = new Schedule(task).everyMinute()
27-
expect((schedule as any).cronPattern).toBe('0 * * * * *')
20+
describe('Schedule methods', () => {
21+
it.each([
22+
['everySecond', '* * * * * *'],
23+
['everyMinute', '0 * * * * *'],
24+
['everyTwoMinutes', '*/2 * * * * *'],
25+
['everyFiveMinutes', '*/5 * * * *'],
26+
['everyTenMinutes', '*/10 * * * *'],
27+
['everyThirtyMinutes', '*/30 * * * *'],
28+
['everyHour', '0 0 * * * *'],
29+
['everyDay', '0 0 0 * * *'],
30+
['hourly', '0 0 * * * *'],
31+
['daily', '0 0 0 * * *'],
32+
['weekly', '0 0 0 * * 0'],
33+
['monthly', '0 0 0 1 * *'],
34+
['yearly', '0 0 0 1 1 *'],
35+
])('should set correct cron pattern for %s', (method, expectedPattern) => {
36+
;(schedule as any)[method]().start()
37+
expect(mockLogInfo).toHaveBeenCalledWith(
38+
`Scheduled task with pattern: ${expectedPattern} in timezone: America/Los_Angeles`,
39+
)
40+
})
41+
42+
it('should set correct cron pattern for onDays', () => {
43+
schedule.onDays([1, 3, 5]).start()
44+
expect(mockLogInfo).toHaveBeenCalledWith(
45+
'Scheduled task with pattern: 0 0 0 * * 1,3,5 in timezone: America/Los_Angeles',
46+
)
47+
})
48+
49+
it('should set correct cron pattern for at', () => {
50+
schedule.at('14:30').start()
51+
expect(mockLogInfo).toHaveBeenCalledWith(
52+
'Scheduled task with pattern: 30 14 * * * in timezone: America/Los_Angeles',
53+
)
2854
})
2955

30-
it('should create a schedule with everyTwoMinutes', () => {
31-
const task = mock(() => {})
32-
const schedule = new Schedule(task).everyTwoMinutes()
33-
expect((schedule as any).cronPattern).toBe('*/2 * * * * *')
34-
})
35-
36-
it('should create a schedule with everyFiveMinutes', () => {
37-
const task = mock(() => {})
38-
const schedule = new Schedule(task).everyFiveMinutes()
39-
expect((schedule as any).cronPattern).toBe('*/5 * * * *')
40-
})
41-
42-
it('should create a schedule with everyTenMinutes', () => {
43-
const task = mock(() => {})
44-
const schedule = new Schedule(task).everyTenMinutes()
45-
expect((schedule as any).cronPattern).toBe('*/10 * * * *')
56+
it('should set timezone', () => {
57+
schedule.daily().setTimeZone('Europe/London').start()
58+
expect(mockLogInfo).toHaveBeenCalledWith('Scheduled task with pattern: 0 0 0 * * * in timezone: Europe/London')
4659
})
60+
})
4761

48-
it('should create a schedule with everyThirtyMinutes', () => {
49-
const task = mock(() => {})
50-
const schedule = new Schedule(task).everyThirtyMinutes()
51-
expect((schedule as any).cronPattern).toBe('*/30 * * * *')
62+
describe('Job and Action methods', () => {
63+
it('should log job scheduling', () => {
64+
schedule.job('path/to/job')
65+
expect(mockLogInfo).toHaveBeenCalledWith('Scheduling job: path/to/job')
5266
})
5367

54-
it('should create a schedule with hourly', () => {
55-
const task = mock(() => {})
56-
const schedule = new Schedule(task).hourly()
57-
expect((schedule as any).cronPattern).toBe('0 0 * * * *')
68+
it('should log action scheduling', () => {
69+
schedule.action('path/to/action')
70+
expect(mockLogInfo).toHaveBeenCalledWith('Scheduling action: path/to/action')
5871
})
72+
})
5973

60-
it('should create a schedule with daily', () => {
61-
const task = mock(() => {})
62-
const schedule = new Schedule(task).daily()
63-
expect((schedule as any).cronPattern).toBe('0 0 0 * * *')
74+
describe('Static command method', () => {
75+
it('should log command execution', () => {
76+
Schedule.command('npm run build')
77+
expect(mockLogInfo).toHaveBeenCalledWith('Executing command: npm run build')
6478
})
79+
})
6580

66-
it('should create a schedule with weekly', () => {
67-
const task = mock(() => {})
68-
const schedule = new Schedule(task).weekly()
69-
expect((schedule as any).cronPattern).toBe('0 0 0 * * 0')
81+
describe('Job class', () => {
82+
it('should inherit from Schedule', () => {
83+
const job = new Job(mockTask)
84+
expect(job).toBeInstanceOf(Schedule)
7085
})
7186

72-
it('should create a schedule with monthly', () => {
73-
const task = mock(() => {})
74-
const schedule = new Schedule(task).monthly()
75-
expect((schedule as any).cronPattern).toBe('0 0 0 1 * *')
87+
it('should have the same methods as Schedule', () => {
88+
const job = new Job(mockTask)
89+
expect(job.everyMinute).toBeDefined()
90+
expect(job.daily).toBeDefined()
91+
expect(job.setTimeZone).toBeDefined()
7692
})
93+
})
7794

78-
it('should create a schedule with yearly', () => {
79-
const task = mock(() => {})
80-
const schedule = new Schedule(task).yearly()
81-
expect((schedule as any).cronPattern).toBe('0 0 0 1 1 *')
95+
describe('sendAt function', () => {
96+
it('should return a DateTime-like object', () => {
97+
const result = sendAt('0 0 * * *')
98+
expect(result).toHaveProperty('year')
99+
expect(result).toHaveProperty('month')
100+
expect(result).toHaveProperty('day')
101+
expect(result).toHaveProperty('hour')
102+
expect(result).toHaveProperty('minute')
103+
expect(result).toHaveProperty('second')
82104
})
83105

84-
it('should create a schedule with onDays', () => {
85-
const task = mock(() => {})
86-
const schedule = new Schedule(task).onDays([1, 3, 5])
87-
expect((schedule as any).cronPattern).toBe('0 0 0 * * 1,3,5')
106+
it('should calculate the next occurrence correctly', () => {
107+
const now = new Date()
108+
const result = sendAt('0 0 * * *')
109+
expect(result.toJSDate() > now).toBe(true)
110+
expect(result.hour).toBe(0)
111+
expect(result.minute).toBe(0)
88112
})
113+
})
89114

90-
it('should create a schedule with at', () => {
91-
const task = mock(() => {})
92-
const schedule = new Schedule(task).at('14:30')
93-
expect((schedule as any).cronPattern).toBe('30 14 * * *')
115+
describe('timeout function', () => {
116+
it('should return a number', () => {
117+
const result = timeout('0 0 * * *')
118+
expect(typeof result).toBe('number')
94119
})
95120

96-
it('should set timezone', () => {
97-
const task = mock(() => {})
98-
const schedule = new Schedule(task).setTimeZone('UTC')
99-
expect((schedule as any).timezone).toBe('UTC')
121+
it('should return a positive number', () => {
122+
const result = timeout('0 0 * * *')
123+
expect(result).toBeGreaterThan(0)
100124
})
125+
})
101126

102-
it('should start the schedule', () => {
103-
const task = mock(() => {})
104-
const schedule = new Schedule(task).everyMinute()
105-
const cronJobSpy = spyOn(CronJob, 'from').mockImplementation(() => ({}) as any)
106-
schedule.start()
107-
expect(cronJobSpy).toHaveBeenCalledWith('0 * * * * *', expect.any(Function), null, true, 'America/Los_Angeles')
108-
})
127+
describe('CronJob integration', () => {
128+
it('should create a CronJob instance when start is called', () => {
129+
const mockTask = mock(() => {})
130+
const schedule = new Schedule(mockTask)
109131

110-
it('should log job scheduling', () => {
111-
const task = mock(() => {})
112-
const logSpy = spyOn(console, 'info')
113-
new Schedule(task).job('/path/to/job')
114-
expect(logSpy).toHaveBeenCalledWith('Scheduling job: /path/to/job')
115-
})
132+
schedule.everySecond().start()
116133

117-
it('should log action scheduling', () => {
118-
const task = mock(() => {})
119-
const logSpy = spyOn(console, 'info')
120-
new Schedule(task).action('/path/to/action')
121-
expect(logSpy).toHaveBeenCalledWith('Scheduling action: /path/to/action')
134+
// Check if mockLogInfo was called with the correct message
135+
expect(mockLogInfo).toHaveBeenCalledWith(
136+
'Scheduled task with pattern: * * * * * * in timezone: America/Los_Angeles',
137+
)
122138
})
123139

124-
it('should log command execution', () => {
125-
const logSpy = spyOn(console, 'info')
126-
Schedule.command('echo "Hello"')
127-
expect(logSpy).toHaveBeenCalledWith('Executing command: echo "Hello"')
128-
})
129-
})
140+
it('should create a CronJob with correct parameters', () => {
141+
const mockTask = mock(() => {})
142+
const schedule = new Schedule(mockTask)
130143

131-
describe('sendAt function', () => {
132-
it('should return correct DateTime for cron string', () => {
133-
const result = sendAt('0 0 * * *')
134-
expect(result).toBeInstanceOf(DateTime)
135-
expect(result.toISO()).toBe('2024-01-02T00:00:00.000Z')
136-
})
144+
schedule.everyMinute().setTimeZone('Europe/London').start()
137145

138-
it('should return correct DateTime for Date object', () => {
139-
const date = new Date('2024-01-01T12:00:00Z')
140-
const result = sendAt(date)
141-
expect(result).toBeInstanceOf(DateTime)
142-
expect(result.toISO()).toBe('2024-01-01T12:00:00.000Z')
146+
expect(mockLogInfo).toHaveBeenCalledWith('Scheduled task with pattern: 0 * * * * * in timezone: Europe/London')
143147
})
144-
})
145148

146-
describe('timeout function', () => {
147-
it('should return correct timeout for cron string', () => {
148-
const result = timeout('0 0 * * *')
149-
expect(result).toBe(86400000) // 24 hours in milliseconds
150-
})
149+
describe('Cron exports', () => {
150+
it('CronJob is exported and can be instantiated', () => {
151+
const job = new CronJob('* * * * *', () => {})
152+
expect(job).toBeInstanceOf(CronJob)
153+
})
151154

152-
it('should return correct timeout for Date object', () => {
153-
const date = new Date('2024-01-01T12:00:00Z')
154-
const result = timeout(date)
155-
expect(result).toBe(43200000) // 12 hours in milliseconds
155+
it('CronTime is exported and can be instantiated', () => {
156+
const time = new CronTime('* * * * *')
157+
expect(time).toBeInstanceOf(CronTime)
158+
})
156159
})
157160
})
158161
})

storage/framework/ide/vscode/.vscode/.cursorrules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ Key Conventions:
4848
- Aim for 100% test coverage
4949
- Use Composition API
5050
- Use setup script
51+
- Avoid usage of any
5152

5253
Follow Vue.js docs for where makes sense

0 commit comments

Comments
 (0)