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