@@ -20,6 +20,7 @@ suite('Common Utils - Decorators', () => {
2020 /*
2121 * Time in milliseconds (from some arbitrary point in time for current process).
2222 * Don't use new Date().getTime() to calculate differences in times.
23+ * Similarly setTimeout doesn't always trigger at prescribed time (accuracy isn't guaranteed).
2324 * This has an accuracy of around 2-20ms.
2425 * However we're dealing with tests that need accuracy of 1ms.
2526 * Use API that'll give us better accuracy when dealing with elapsed times.
@@ -31,6 +32,28 @@ suite('Common Utils - Decorators', () => {
3132 // Convert seconds to ms and nanoseconds to ms.
3233 return ( currentTime [ 0 ] * 1000 ) + ( currentTime [ 1 ] / 1000_000 ) ;
3334 }
35+
36+ /**
37+ * setTimeout doesn't always trigger at prescribed time (accuracy isn't guaranteed).
38+ * Allow a discrepancy of +-5%.
39+ * Here's a simple test to prove this (this has been reported by others too):
40+ * ```js
41+ * // Execute the following around 100 times, you'll see at least one where elapsed time is < 100.
42+ * const startTime = ....
43+ * await new Promise(resolve = setTimeout(resolve, 100))
44+ * console.log(currentTime - startTijme)
45+ * ```
46+ *
47+ * @param {number } actualDelay
48+ * @param {number } expectedDelay
49+ */
50+ function assertElapsedTimeWithinRange ( actualDelay : number , expectedDelay : number ) {
51+ const difference = actualDelay - expectedDelay ;
52+ if ( difference >= 0 ) {
53+ return ;
54+ }
55+ expect ( Math . abs ( difference ) ) . to . be . lessThan ( expectedDelay * 0.05 , `Actual delay ${ actualDelay } , expected delay ${ expectedDelay } , not within 5% of accuracy` ) ;
56+ }
3457 function createMockVSC ( pythonPath : string ) : typeof import ( 'vscode' ) {
3558 return {
3659 workspace : {
@@ -162,7 +185,7 @@ suite('Common Utils - Decorators', () => {
162185 await waitForCalls ( one . timestamps , 1 ) ;
163186 const delay = one . timestamps [ 0 ] - start ;
164187
165- expect ( delay ) . to . be . at . least ( wait ) ;
188+ assertElapsedTimeWithinRange ( delay , wait ) ;
166189 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
167190 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
168191 } ) ;
@@ -183,7 +206,7 @@ suite('Common Utils - Decorators', () => {
183206 await waitForCalls ( one . timestamps , 1 ) ;
184207 const delay = one . timestamps [ 0 ] - start ;
185208
186- expect ( delay ) . to . be . at . least ( wait ) ;
209+ assertElapsedTimeWithinRange ( delay , wait ) ;
187210 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
188211 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
189212 expect ( errored ) . to . be . equal ( false , 'Exception raised when there shouldn\'t have been any' ) ;
@@ -204,7 +227,7 @@ suite('Common Utils - Decorators', () => {
204227 await waitForCalls ( one . timestamps , 1 ) ;
205228 const delay = one . timestamps [ 0 ] - start ;
206229
207- expect ( delay ) . to . be . at . least ( wait ) ;
230+ assertElapsedTimeWithinRange ( delay , wait ) ;
208231 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
209232 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
210233 } ) ;
@@ -226,7 +249,7 @@ suite('Common Utils - Decorators', () => {
226249 await waitForCalls ( one . timestamps , 1 ) ;
227250 const delay = one . timestamps [ 0 ] - start ;
228251
229- expect ( delay ) . to . be . at . least ( wait ) ;
252+ assertElapsedTimeWithinRange ( delay , wait ) ;
230253 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
231254 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
232255 expect ( capturedEx ) . to . not . be . equal ( undefined , 'Exception not re-thrown' ) ;
@@ -251,7 +274,7 @@ suite('Common Utils - Decorators', () => {
251274 await waitForCalls ( one . timestamps , 1 ) ;
252275 const delay = one . timestamps [ 0 ] - start ;
253276
254- expect ( delay ) . to . be . at . least ( wait ) ;
277+ assertElapsedTimeWithinRange ( delay , wait ) ;
255278 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
256279 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
257280 expect ( errored ) . to . be . equal ( false , 'Exception raised when there shouldn\'t have been any' ) ;
@@ -273,7 +296,7 @@ suite('Common Utils - Decorators', () => {
273296 await waitForCalls ( one . timestamps , 1 ) ;
274297 const delay = one . timestamps [ 0 ] - start ;
275298
276- expect ( delay ) . to . be . at . least ( wait ) ;
299+ assertElapsedTimeWithinRange ( delay , wait ) ;
277300 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
278301 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
279302 } ) ;
@@ -297,7 +320,7 @@ suite('Common Utils - Decorators', () => {
297320 await waitForCalls ( one . timestamps , 2 ) ;
298321 const delay = one . timestamps [ 1 ] - start ;
299322
300- expect ( delay ) . to . be . at . least ( wait ) ;
323+ assertElapsedTimeWithinRange ( delay , wait ) ;
301324 expect ( one . calls ) . to . deep . equal ( [ 'run' , 'run' ] ) ;
302325 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
303326 expect ( errored ) . to . be . equal ( false , 'Exception raised when there shouldn\'t have been any' ) ;
@@ -320,7 +343,7 @@ suite('Common Utils - Decorators', () => {
320343 await waitForCalls ( one . timestamps , 1 ) ;
321344 const delay = one . timestamps [ 0 ] - start ;
322345
323- expect ( delay ) . to . be . at . least ( wait ) ;
346+ assertElapsedTimeWithinRange ( delay , wait ) ;
324347 expect ( one . calls ) . to . deep . equal ( [ 'run' ] ) ;
325348 expect ( one . timestamps ) . to . have . lengthOf ( one . calls . length ) ;
326349 } ) ;
0 commit comments