1
+ import { describe , it , expect , assert , vi } from "vitest" ;
2
+ import { actor , setup } from "@/mod" ;
3
+ import { setupTest } from "@/test/mod" ;
4
+ import type { Alarm } from "@/actor/schedule" ;
5
+
6
+ describe ( "Actor scheduling" , ( ) => {
7
+ // Increase timeout for scheduling tests
8
+ it ( "should schedule and execute events after specified duration" , async ( ) => {
9
+ const events : string [ ] = [ ] ;
10
+
11
+ const testActor = actor ( {
12
+ state : {
13
+ events : [ ] as string [ ] ,
14
+ done : false
15
+ } ,
16
+ actions : {
17
+ scheduleEvents : async ( c ) => {
18
+ await c . schedule . after ( 100 , "recordEvent" , "event1" ) ;
19
+ await c . schedule . after ( 200 , "recordEvent" , "event2" ) ;
20
+ } ,
21
+ recordEvent : ( c , event : string ) => {
22
+ events . push ( event ) ;
23
+ if ( events . length === 2 ) {
24
+ c . state . done = true ;
25
+ }
26
+ } ,
27
+ isDone : ( c ) => c . state . done
28
+ }
29
+ } ) ;
30
+
31
+ const app = setup ( {
32
+ actors : { testActor }
33
+ } ) ;
34
+
35
+ const { client } = await setupTest ( app ) ;
36
+ const instance = await client . testActor . get ( ) ;
37
+
38
+ await instance . scheduleEvents ( ) ;
39
+
40
+ // Advance time to trigger both events
41
+ await vi . advanceTimersByTimeAsync ( 250 ) ;
42
+
43
+ expect ( events ) . toEqual ( [ "event1" , "event2" ] ) ;
44
+ } ) ;
45
+
46
+ it ( "should schedule events at specific timestamps" , async ( ) => {
47
+ const events : string [ ] = [ ] ;
48
+
49
+ const testActor = actor ( {
50
+ state : {
51
+ events : [ ] as string [ ] ,
52
+ done : false
53
+ } ,
54
+ actions : {
55
+ scheduleEvents : async ( c ) => {
56
+ const now = Date . now ( ) ;
57
+ await c . schedule . at ( now + 100 , "recordEvent" , "event1" ) ;
58
+ await c . schedule . at ( now + 200 , "recordEvent" , "event2" ) ;
59
+ } ,
60
+ recordEvent : ( c , event : string ) => {
61
+ events . push ( event ) ;
62
+ if ( events . length === 2 ) {
63
+ c . state . done = true ;
64
+ }
65
+ } ,
66
+ isDone : ( c ) => c . state . done
67
+ }
68
+ } ) ;
69
+
70
+ const app = setup ( {
71
+ actors : { testActor }
72
+ } ) ;
73
+
74
+ const { client } = await setupTest ( app ) ;
75
+ const instance = await client . testActor . get ( ) ;
76
+
77
+ await instance . scheduleEvents ( ) ;
78
+
79
+ // Advance time to trigger both events
80
+ await vi . advanceTimersByTimeAsync ( 250 ) ;
81
+
82
+ expect ( events ) . toEqual ( [ "event1" , "event2" ] ) ;
83
+ } ) ;
84
+
85
+ it ( "should allow canceling scheduled events" , async ( ) => {
86
+ const events : string [ ] = [ ] ;
87
+ let eventId2 : string ;
88
+
89
+ const testActor = actor ( {
90
+ state : {
91
+ events : [ ] as string [ ] ,
92
+ done : false
93
+ } ,
94
+ actions : {
95
+ scheduleEvents : async ( c ) => {
96
+ await c . schedule . after ( 100 , "recordEvent" , "event1" ) ;
97
+ eventId2 = await c . schedule . after ( 200 , "recordEvent" , "event2" ) ;
98
+ } ,
99
+ cancelEvent : async ( c ) => {
100
+ await c . schedule . cancel ( eventId2 ) ;
101
+ } ,
102
+ recordEvent : ( c , event : string ) => {
103
+ events . push ( event ) ;
104
+ } ,
105
+ isDone : ( c ) => c . state . done
106
+ }
107
+ } ) ;
108
+
109
+ const app = setup ( {
110
+ actors : { testActor }
111
+ } ) ;
112
+
113
+ const { client } = await setupTest ( app ) ;
114
+ const instance = await client . testActor . get ( ) ;
115
+
116
+ await instance . scheduleEvents ( ) ;
117
+ await instance . cancelEvent ( ) ;
118
+
119
+ // Advance time to trigger all events except the cancelled one
120
+ await vi . advanceTimersByTimeAsync ( 700 ) ;
121
+
122
+ expect ( events ) . toEqual ( [ "event1" ] ) ;
123
+ } ) ;
124
+
125
+ it ( "should list all scheduled events" , async ( ) => {
126
+ const testActor = actor ( {
127
+ state : {
128
+ scheduledEvents : null as readonly Alarm [ ] | null
129
+ } ,
130
+ actions : {
131
+ scheduleAndList : async ( c ) => {
132
+ await c . schedule . after ( 1000 , "doSomething" ) ;
133
+ await c . schedule . after ( 2000 , "doSomething" ) ;
134
+ c . state . scheduledEvents = await c . schedule . list ( ) ;
135
+ } ,
136
+ getScheduledEvents : ( c ) => c . state . scheduledEvents ,
137
+ doSomething : ( ) => { }
138
+ }
139
+ } ) ;
140
+
141
+ const app = setup ( {
142
+ actors : { testActor }
143
+ } ) ;
144
+
145
+ const { client } = await setupTest ( app ) ;
146
+ const instance = await client . testActor . get ( ) ;
147
+
148
+ const now = Date . now ( ) ;
149
+ await instance . scheduleAndList ( ) ;
150
+ const scheduledEvents = await instance . getScheduledEvents ( ) ;
151
+
152
+ expect ( scheduledEvents ) . toHaveLength ( 2 ) ;
153
+ assert ( scheduledEvents , "scheduledEvents should not be null" ) ;
154
+ expect ( scheduledEvents [ 0 ] . triggersAt ) . toBeGreaterThan ( now ) ;
155
+ expect ( scheduledEvents [ 1 ] . triggersAt ) . toBeGreaterThan ( scheduledEvents [ 0 ] . triggersAt ) ;
156
+ } ) ;
157
+
158
+ it ( "should get details of a specific scheduled event" , async ( ) => {
159
+ const testActor = actor ( {
160
+ state : {
161
+ eventDetails : null as Alarm | null ,
162
+ eventId : "" as string
163
+ } ,
164
+ actions : {
165
+ scheduleAndGet : async ( c ) => {
166
+ c . state . eventId = await c . schedule . after ( 1000 , "doSomething" , "arg1" , 42 ) ;
167
+ const details = await c . schedule . get ( c . state . eventId ) ;
168
+ c . state . eventDetails = details || null ;
169
+ } ,
170
+ getEventDetails : ( c ) => ( {
171
+ details : c . state . eventDetails ,
172
+ id : c . state . eventId
173
+ } ) ,
174
+ doSomething : ( ) => { }
175
+ }
176
+ } ) ;
177
+
178
+ const app = setup ( {
179
+ actors : { testActor }
180
+ } ) ;
181
+
182
+ const { client } = await setupTest ( app ) ;
183
+ const instance = await client . testActor . get ( ) ;
184
+
185
+ const now = Date . now ( ) ;
186
+ await instance . scheduleAndGet ( ) ;
187
+ const { details : eventDetails , id : eventId } = await instance . getEventDetails ( ) ;
188
+
189
+ expect ( eventDetails ) . toBeDefined ( ) ;
190
+ expect ( eventDetails ?. id ) . toBe ( eventId ) ;
191
+ expect ( eventDetails ?. fn ) . toBe ( "doSomething" ) ;
192
+ expect ( eventDetails ?. args ) . toEqual ( [ "arg1" , 42 ] ) ;
193
+ expect ( eventDetails ?. triggersAt ) . toBeGreaterThan ( now ) ;
194
+ expect ( eventDetails ?. createdAt ) . toBeLessThanOrEqual ( now ) ;
195
+ } ) ;
196
+ } ) ;
0 commit comments