1
1
import { describe , expect , test , vi } from 'vitest' ;
2
2
import { makePromiseBuffer } from '../../../src/utils/promisebuffer' ;
3
- import { SyncPromise } from '../../../src/utils/syncpromise' ;
3
+ import { rejectedSyncPromise , resolvedSyncPromise } from '../../../src/utils/syncpromise' ;
4
4
5
5
describe ( 'PromiseBuffer' , ( ) => {
6
6
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 ( ) ;
12
63
} ) ;
13
64
14
- test ( 'with limit' , ( ) => {
65
+ test ( 'async promises' , async ( ) => {
15
66
const buffer = makePromiseBuffer ( 1 ) ;
16
67
let task1 ;
17
68
const producer1 = vi . fn ( ( ) => {
18
- task1 = new SyncPromise ( resolve => setTimeout ( resolve ) ) ;
69
+ task1 = new Promise ( resolve => setTimeout ( resolve , 1 ) ) ;
19
70
return task1 ;
20
71
} ) ;
21
- const producer2 = vi . fn ( ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ) ;
72
+ const producer2 = vi . fn ( ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ) ;
22
73
expect ( buffer . add ( producer1 ) ) . toEqual ( task1 ) ;
23
- void expect ( buffer . add ( producer2 ) ) . rejects . toThrowError ( ) ;
74
+ const add2 = buffer . add ( producer2 ) ;
75
+
24
76
expect ( buffer . $ . length ) . toEqual ( 1 ) ;
77
+
78
+ await expect ( add2 ) . rejects . toThrowError ( ) ;
79
+
25
80
expect ( producer1 ) . toHaveBeenCalled ( ) ;
26
81
expect ( producer2 ) . not . toHaveBeenCalled ( ) ;
27
82
} ) ;
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
+ } ) ;
28
104
} ) ;
29
105
30
106
describe ( 'drain()' , ( ) => {
31
- test ( 'without timeout' , async ( ) => {
107
+ test ( 'drains all promises without timeout' , async ( ) => {
32
108
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
+
36
120
expect ( buffer . $ . length ) . toEqual ( 5 ) ;
37
121
const result = await buffer . drain ( ) ;
38
122
expect ( result ) . toEqual ( true ) ;
39
123
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 ( ) ;
40
130
} ) ;
41
131
42
- test ( 'with timeout' , async ( ) => {
132
+ test ( 'drains all promises with timeout' , async ( ) => {
43
133
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
+
47
151
expect ( buffer . $ . length ) . toEqual ( 5 ) ;
48
- const result = await buffer . drain ( 50 ) ;
152
+ const result = await buffer . drain ( 8 ) ;
49
153
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 ) ;
50
161
} ) ;
51
162
52
163
test ( 'on empty buffer' , async ( ) => {
@@ -56,11 +167,26 @@ describe('PromiseBuffer', () => {
56
167
expect ( result ) . toEqual ( true ) ;
57
168
expect ( buffer . $ . length ) . toEqual ( 0 ) ;
58
169
} ) ;
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
+ } ) ;
59
185
} ) ;
60
186
61
187
test ( 'resolved promises should not show up in buffer length' , async ( ) => {
62
188
const buffer = makePromiseBuffer ( ) ;
63
- const producer = ( ) => new SyncPromise ( resolve => setTimeout ( resolve ) ) ;
189
+ const producer = ( ) => new Promise ( resolve => setTimeout ( resolve , 1 ) ) ;
64
190
const task = buffer . add ( producer ) ;
65
191
expect ( buffer . $ . length ) . toEqual ( 1 ) ;
66
192
await task ;
@@ -69,20 +195,18 @@ describe('PromiseBuffer', () => {
69
195
70
196
test ( 'rejected promises should not show up in buffer length' , async ( ) => {
71
197
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 ) ) ;
73
200
const task = buffer . add ( producer ) ;
74
201
expect ( buffer . $ . length ) . toEqual ( 1 ) ;
75
- try {
76
- await task ;
77
- } catch {
78
- // no-empty
79
- }
202
+
203
+ await expect ( task ) . rejects . toThrow ( error ) ;
80
204
expect ( buffer . $ . length ) . toEqual ( 0 ) ;
81
205
} ) ;
82
206
83
207
test ( 'resolved task should give an access to the return value' , async ( ) => {
84
208
const buffer = makePromiseBuffer < string > ( ) ;
85
- const producer = ( ) => new SyncPromise < string > ( resolve => setTimeout ( ( ) => resolve ( 'test' ) ) ) ;
209
+ const producer = ( ) => resolvedSyncPromise ( 'test' ) ;
86
210
const task = buffer . add ( producer ) ;
87
211
const result = await task ;
88
212
expect ( result ) . toEqual ( 'test' ) ;
@@ -91,7 +215,7 @@ describe('PromiseBuffer', () => {
91
215
test ( 'rejected task should give an access to the return value' , async ( ) => {
92
216
expect . assertions ( 1 ) ;
93
217
const buffer = makePromiseBuffer < string > ( ) ;
94
- const producer = ( ) => new SyncPromise < string > ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( 'whoops' ) ) ) ) ;
218
+ const producer = ( ) => rejectedSyncPromise ( new Error ( 'whoops' ) ) ;
95
219
const task = buffer . add ( producer ) ;
96
220
try {
97
221
await task ;
0 commit comments