1
- import { Container , ContainerModule } from '@theia/core/shared/inversify' ;
1
+ import {
2
+ Container ,
3
+ ContainerModule ,
4
+ injectable ,
5
+ } from '@theia/core/shared/inversify' ;
2
6
import { assert , expect } from 'chai' ;
3
7
import fetch from 'cross-fetch' ;
4
8
import { posix } from 'path' ;
@@ -19,13 +23,14 @@ import queryString = require('query-string');
19
23
const timeout = 60 * 1_000 ;
20
24
21
25
describe ( 'create-api' , ( ) => {
22
- let createApi : CreateApi ;
26
+ let createApi : TestCreateApi ;
23
27
24
28
before ( async function ( ) {
25
29
this . timeout ( timeout ) ;
26
30
try {
27
31
const accessToken = await login ( ) ;
28
- createApi = createContainer ( accessToken ) . get < CreateApi > ( CreateApi ) ;
32
+ createApi =
33
+ createContainer ( accessToken ) . get < TestCreateApi > ( TestCreateApi ) ;
29
34
} catch ( err ) {
30
35
if ( err instanceof LoginFailed ) {
31
36
return this . skip ( ) ;
@@ -43,7 +48,7 @@ describe('create-api', () => {
43
48
const container = new Container ( { defaultScope : 'Singleton' } ) ;
44
49
container . load (
45
50
new ContainerModule ( ( bind ) => {
46
- bind ( CreateApi ) . toSelf ( ) . inSingletonScope ( ) ;
51
+ bind ( TestCreateApi ) . toSelf ( ) . inSingletonScope ( ) ;
47
52
bind ( SketchCache ) . toSelf ( ) . inSingletonScope ( ) ;
48
53
bind ( AuthenticationClientService ) . toConstantValue ( <
49
54
AuthenticationClientService
@@ -224,6 +229,47 @@ describe('create-api', () => {
224
229
expect ( findByName ( otherName , sketches ) ) . to . be . not . undefined ;
225
230
} ) ;
226
231
232
+ [
233
+ [ - 1 , 1 ] ,
234
+ [ 0 , 2 ] ,
235
+ [ 1 , 2 ] ,
236
+ ] . forEach ( ( [ diff , expected ] ) =>
237
+ it ( `should not run unnecessary fetches when retrieving all sketches (sketch count ${
238
+ diff < 0 ? '<' : diff > 0 ? '>' : '='
239
+ } limit)`, async ( ) => {
240
+ const content = 'void setup(){} void loop(){}' ;
241
+ const maxLimit = 50 ; // https://github.com/arduino/arduino-ide/pull/875
242
+ const sketchCount = maxLimit + diff ;
243
+ const sketchNames = [ ...Array ( sketchCount ) . keys ( ) ] . map ( ( ) => v4 ( ) ) ;
244
+
245
+ await sketchNames
246
+ . map ( ( name ) => createApi . createSketch ( toPosix ( name ) , content ) )
247
+ . reduce ( async ( acc , curr ) => {
248
+ await acc ;
249
+ return curr ;
250
+ } , Promise . resolve ( ) as Promise < unknown > ) ;
251
+
252
+ createApi . resetRequestRecording ( ) ;
253
+ const sketches = await createApi . sketches ( ) ;
254
+ const allRequests = createApi . requestRecording . slice ( ) ;
255
+
256
+ expect ( sketches . length ) . to . be . equal ( sketchCount ) ;
257
+ sketchNames . forEach (
258
+ ( name ) => expect ( findByName ( name , sketches ) ) . to . be . not . undefined
259
+ ) ;
260
+
261
+ expect ( allRequests . length ) . to . be . equal ( expected ) ;
262
+ const getSketchesRequests = allRequests . filter (
263
+ ( description ) =>
264
+ description . method === 'GET' &&
265
+ description . pathname === '/create/v2/sketches' &&
266
+ description . query &&
267
+ description . query . includes ( `limit=${ maxLimit } ` )
268
+ ) ;
269
+ expect ( getSketchesRequests . length ) . to . be . equal ( expected ) ;
270
+ } )
271
+ ) ;
272
+
227
273
[ '.' , '-' , '_' ] . map ( ( char ) => {
228
274
it ( `should create a new sketch with '${ char } ' in the sketch folder name although it's disallowed from the Create Editor` , async ( ) => {
229
275
const name = `sketch${ char } ` ;
@@ -332,3 +378,44 @@ class LoginFailed extends Error {
332
378
Object . setPrototypeOf ( this , LoginFailed . prototype ) ;
333
379
}
334
380
}
381
+
382
+ @injectable ( )
383
+ class TestCreateApi extends CreateApi {
384
+ private _recording : RequestDescription [ ] = [ ] ;
385
+
386
+ constructor ( ) {
387
+ super ( ) ;
388
+ const originalRun = this [ 'run' ] ;
389
+ this [ 'run' ] = ( url , init , resultProvider ) => {
390
+ this . _recording . push ( createRequestDescription ( url , init ) ) ;
391
+ return originalRun . bind ( this ) ( url , init , resultProvider ) ;
392
+ } ;
393
+ }
394
+
395
+ resetRequestRecording ( ) : void {
396
+ this . _recording = [ ] ;
397
+ }
398
+
399
+ get requestRecording ( ) : RequestDescription [ ] {
400
+ return this . _recording ;
401
+ }
402
+ }
403
+
404
+ interface RequestDescription {
405
+ readonly origin : string ;
406
+ readonly pathname : string ;
407
+ readonly query ?: string ;
408
+
409
+ readonly method ?: string | undefined ;
410
+ readonly serializedBody ?: string | undefined ;
411
+ }
412
+
413
+ function createRequestDescription (
414
+ url : URL ,
415
+ init ?: RequestInit | undefined
416
+ ) : RequestDescription {
417
+ const { origin, pathname, search : query } = url ;
418
+ const method = init ?. method ;
419
+ const serializedBody = init ?. body ?. toString ( ) ;
420
+ return { origin, pathname, query, method, serializedBody } ;
421
+ }
0 commit comments