11import { describe , expect , test , vi } from 'vitest' ;
22import { makePromiseBuffer } from '../../../src/utils/promisebuffer' ;
3- import { SyncPromise } from '../../../src/utils/syncpromise' ;
3+ import { rejectedSyncPromise , resolvedSyncPromise } from '../../../src/utils/syncpromise' ;
44
55describe ( 'PromiseBuffer' , ( ) => {
66 describe ( 'add()' , ( ) => {
7- test ( 'no limit' , ( ) => {
8- const buffer = makePromiseBuffer ( ) ;
9- const p = vi . fn ( ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ) ;
10- void buffer . add ( p ) ;
11- expect ( buffer . $ . length ) . toEqual ( 1 ) ;
7+ test ( 'enforces limit of promises' , async ( ) => {
8+ const buffer = makePromiseBuffer ( 5 ) ;
9+
10+ const producer1 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
11+ const producer2 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
12+ const producer3 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
13+ const producer4 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
14+ const producer5 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
15+ const producer6 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
16+
17+ void buffer . add ( producer1 ) ;
18+ void buffer . add ( producer2 ) ;
19+ void buffer . add ( producer3 ) ;
20+ void buffer . add ( producer4 ) ;
21+ void buffer . add ( producer5 ) ;
22+ await expect ( buffer . add ( producer6 ) ) . rejects . toThrowError ( ) ;
23+
24+ expect ( producer1 ) . toHaveBeenCalledTimes ( 1 ) ;
25+ expect ( producer2 ) . toHaveBeenCalledTimes ( 1 ) ;
26+ expect ( producer3 ) . toHaveBeenCalledTimes ( 1 ) ;
27+ expect ( producer4 ) . toHaveBeenCalledTimes ( 1 ) ;
28+ expect ( producer5 ) . toHaveBeenCalledTimes ( 1 ) ;
29+ expect ( producer6 ) . not . toHaveBeenCalled ( ) ;
30+
31+ expect ( buffer . $ . length ) . toEqual ( 5 ) ;
32+
33+ await buffer . drain ( ) ;
34+
35+ expect ( buffer . $ . length ) . toEqual ( 0 ) ;
36+
37+ expect ( producer1 ) . toHaveBeenCalledTimes ( 1 ) ;
38+ expect ( producer2 ) . toHaveBeenCalledTimes ( 1 ) ;
39+ expect ( producer3 ) . toHaveBeenCalledTimes ( 1 ) ;
40+ expect ( producer4 ) . toHaveBeenCalledTimes ( 1 ) ;
41+ expect ( producer5 ) . toHaveBeenCalledTimes ( 1 ) ;
42+ expect ( producer6 ) . not . toHaveBeenCalled ( ) ;
43+ } ) ;
44+
45+ test ( 'sync promises' , async ( ) => {
46+ const buffer = makePromiseBuffer ( 1 ) ;
47+ let task1 ;
48+ const producer1 = vi . fn ( ( ) => {
49+ task1 = resolvedSyncPromise ( ) ;
50+ return task1 ;
51+ } ) ;
52+ const producer2 = vi . fn ( ( ) => resolvedSyncPromise ( ) ) ;
53+ expect ( buffer . add ( producer1 ) ) . toEqual ( task1 ) ;
54+ const add2 = buffer . add ( producer2 ) ;
55+
56+ // This is immediately executed and removed again from the buffer
57+ expect ( buffer . $ . length ) . toEqual ( 0 ) ;
58+
59+ await expect ( add2 ) . resolves . toBeUndefined ( ) ;
60+
61+ expect ( producer1 ) . toHaveBeenCalled ( ) ;
62+ expect ( producer2 ) . toHaveBeenCalled ( ) ;
1263 } ) ;
1364
14- test ( 'with limit' , ( ) => {
65+ test ( 'async promises' , async ( ) => {
1566 const buffer = makePromiseBuffer ( 1 ) ;
1667 let task1 ;
1768 const producer1 = vi . fn ( ( ) => {
18- task1 = new SyncPromise ( resolve => setTimeout ( resolve ) ) ;
69+ task1 = new Promise ( resolve => setTimeout ( resolve , 1 ) ) ;
1970 return task1 ;
2071 } ) ;
21- const producer2 = vi . fn ( ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ) ;
72+ const producer2 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
2273 expect ( buffer . add ( producer1 ) ) . toEqual ( task1 ) ;
23- void expect ( buffer . add ( producer2 ) ) . rejects . toThrowError ( ) ;
74+ const add2 = buffer . add ( producer2 ) ;
75+
2476 expect ( buffer . $ . length ) . toEqual ( 1 ) ;
77+
78+ await expect ( add2 ) . rejects . toThrowError ( ) ;
79+
2580 expect ( producer1 ) . toHaveBeenCalled ( ) ;
2681 expect ( producer2 ) . not . toHaveBeenCalled ( ) ;
2782 } ) ;
83+
84+ test ( 'handles multiple equivalent promises' , async ( ) => {
85+ const buffer = makePromiseBuffer ( 10 ) ;
86+
87+ const promise = new Promise ( resolve => setTimeout ( resolve , 1 ) ) ;
88+
89+ const producer = vi . fn ( ( ) => promise ) ;
90+ const producer2 = vi . fn ( ( ) => promise ) ;
91+
92+ expect ( buffer . add ( producer ) ) . toEqual ( promise ) ;
93+ expect ( buffer . add ( producer2 ) ) . toEqual ( promise ) ;
94+
95+ expect ( buffer . $ . length ) . toEqual ( 1 ) ;
96+
97+ expect ( producer ) . toHaveBeenCalled ( ) ;
98+ expect ( producer2 ) . toHaveBeenCalled ( ) ;
99+
100+ await buffer . drain ( ) ;
101+
102+ expect ( buffer . $ . length ) . toEqual ( 0 ) ;
103+ } ) ;
28104 } ) ;
29105
30106 describe ( 'drain()' , ( ) => {
31- test ( 'without timeout' , async ( ) => {
107+ test ( 'drains all promises without timeout' , async ( ) => {
32108 const buffer = makePromiseBuffer ( ) ;
33- for ( let i = 0 ; i < 5 ; i ++ ) {
34- void buffer . add ( ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ) ;
35- }
109+
110+ const p1 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
111+ const p2 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
112+ const p3 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
113+ const p4 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
114+ const p5 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
115+
116+ [ p1 , p2 , p3 , p4 , p5 ] . forEach ( p => {
117+ void buffer . add ( p ) ;
118+ } ) ;
119+
36120 expect ( buffer . $ . length ) . toEqual ( 5 ) ;
37121 const result = await buffer . drain ( ) ;
38122 expect ( result ) . toEqual ( true ) ;
39123 expect ( buffer . $ . length ) . toEqual ( 0 ) ;
124+
125+ expect ( p1 ) . toHaveBeenCalled ( ) ;
126+ expect ( p2 ) . toHaveBeenCalled ( ) ;
127+ expect ( p3 ) . toHaveBeenCalled ( ) ;
128+ expect ( p4 ) . toHaveBeenCalled ( ) ;
129+ expect ( p5 ) . toHaveBeenCalled ( ) ;
40130 } ) ;
41131
42- test ( 'with timeout' , async ( ) => {
132+ test ( 'drains all promises with timeout' , async ( ) => {
43133 const buffer = makePromiseBuffer ( ) ;
44- for ( let i = 0 ; i < 5 ; i ++ ) {
45- void buffer . add ( ( ) => new SyncPromise ( resolve => setTimeout ( resolve , 100 ) ) ) ;
46- }
134+
135+ const p1 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 2 ) ) ) ;
136+ const p2 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 4 ) ) ) ;
137+ const p3 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 6 ) ) ) ;
138+ const p4 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 8 ) ) ) ;
139+ const p5 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 10 ) ) ) ;
140+
141+ [ p1 , p2 , p3 , p4 , p5 ] . forEach ( p => {
142+ void buffer . add ( p ) ;
143+ } ) ;
144+
145+ expect ( p1 ) . toHaveBeenCalled ( ) ;
146+ expect ( p2 ) . toHaveBeenCalled ( ) ;
147+ expect ( p3 ) . toHaveBeenCalled ( ) ;
148+ expect ( p4 ) . toHaveBeenCalled ( ) ;
149+ expect ( p5 ) . toHaveBeenCalled ( ) ;
150+
47151 expect ( buffer . $ . length ) . toEqual ( 5 ) ;
48- const result = await buffer . drain ( 50 ) ;
152+ const result = await buffer . drain ( 8 ) ;
49153 expect ( result ) . toEqual ( false ) ;
154+ // p5 is still in the buffer
155+ expect ( buffer . $ . length ) . toEqual ( 1 ) ;
156+
157+ // Now drain final item
158+ const result2 = await buffer . drain ( ) ;
159+ expect ( result2 ) . toEqual ( true ) ;
160+ expect ( buffer . $ . length ) . toEqual ( 0 ) ;
50161 } ) ;
51162
52163 test ( 'on empty buffer' , async ( ) => {
@@ -56,11 +167,26 @@ describe('PromiseBuffer', () => {
56167 expect ( result ) . toEqual ( true ) ;
57168 expect ( buffer . $ . length ) . toEqual ( 0 ) ;
58169 } ) ;
170+
171+ test ( 'resolves even if one of the promises rejects' , async ( ) => {
172+ const buffer = makePromiseBuffer ( ) ;
173+ const p1 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
174+ const p2 = vi . fn ( ( ) => new Promise ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( 'whoops' ) ) , 1 ) ) ) ;
175+ void buffer . add ( p1 ) ;
176+ void buffer . add ( p2 ) ;
177+
178+ const result = await buffer . drain ( ) ;
179+ expect ( result ) . toEqual ( true ) ;
180+ expect ( buffer . $ . length ) . toEqual ( 0 ) ;
181+
182+ expect ( p1 ) . toHaveBeenCalled ( ) ;
183+ expect ( p2 ) . toHaveBeenCalled ( ) ;
184+ } ) ;
59185 } ) ;
60186
61187 test ( 'resolved promises should not show up in buffer length' , async ( ) => {
62188 const buffer = makePromiseBuffer ( ) ;
63- const producer = ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ;
189+ const producer = ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ;
64190 const task = buffer . add ( producer ) ;
65191 expect ( buffer . $ . length ) . toEqual ( 1 ) ;
66192 await task ;
@@ -69,20 +195,18 @@ describe('PromiseBuffer', () => {
69195
70196 test ( 'rejected promises should not show up in buffer length' , async ( ) => {
71197 const buffer = makePromiseBuffer ( ) ;
72- const producer = ( ) => new SyncPromise ( ( _ , reject ) => setTimeout ( reject ) ) ;
198+ const error = new Error ( 'whoops' ) ;
199+ const producer = ( ) => new Promise ( ( _ , reject ) => setTimeout ( ( ) => reject ( error ) , 1 ) ) ;
73200 const task = buffer . add ( producer ) ;
74201 expect ( buffer . $ . length ) . toEqual ( 1 ) ;
75- try {
76- await task ;
77- } catch {
78- // no-empty
79- }
202+
203+ await expect ( task ) . rejects . toThrow ( error ) ;
80204 expect ( buffer . $ . length ) . toEqual ( 0 ) ;
81205 } ) ;
82206
83207 test ( 'resolved task should give an access to the return value' , async ( ) => {
84208 const buffer = makePromiseBuffer < string > ( ) ;
85- const producer = ( ) => new SyncPromise < string > ( resolve => setTimeout ( ( ) => resolve ( 'test' ) ) ) ;
209+ const producer = ( ) => resolvedSyncPromise ( 'test' ) ;
86210 const task = buffer . add ( producer ) ;
87211 const result = await task ;
88212 expect ( result ) . toEqual ( 'test' ) ;
@@ -91,7 +215,7 @@ describe('PromiseBuffer', () => {
91215 test ( 'rejected task should give an access to the return value' , async ( ) => {
92216 expect . assertions ( 1 ) ;
93217 const buffer = makePromiseBuffer < string > ( ) ;
94- const producer = ( ) => new SyncPromise < string > ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( 'whoops' ) ) ) ) ;
218+ const producer = ( ) => rejectedSyncPromise ( new Error ( 'whoops' ) ) ;
95219 const task = buffer . add ( producer ) ;
96220 try {
97221 await task ;
0 commit comments