@@ -10,16 +10,24 @@ const makeFsExtraMock = require('./fs-extra.mock');
1010chai . use ( require ( 'sinon-chai' ) ) ;
1111const expect = chai . expect ;
1212
13+ const globMock = {
14+ sync ( ) { }
15+ } ;
16+
1317describe ( 'validate' , ( ) => {
1418 let fsExtraMock ;
1519 let baseModule ;
1620 let module ;
1721 let serverless ;
22+ let sandbox ;
1823
1924 before ( ( ) => {
25+ sandbox = sinon . sandbox . create ( ) ;
26+
2027 mockery . enable ( { warnOnUnregistered : false } ) ;
2128 fsExtraMock = makeFsExtraMock ( ) ;
2229 mockery . registerMock ( 'fs-extra' , fsExtraMock ) ;
30+ mockery . registerMock ( 'glob' , globMock ) ;
2331 baseModule = require ( '../lib/validate' ) ;
2432 Object . freeze ( baseModule ) ;
2533 } ) ;
@@ -31,13 +39,20 @@ describe('validate', () => {
3139
3240 beforeEach ( ( ) => {
3341 serverless = new Serverless ( ) ;
42+ serverless . cli = {
43+ log : sandbox . stub ( )
44+ } ;
3445 fsExtraMock . _resetSpies ( ) ;
3546 module = Object . assign ( {
3647 serverless,
3748 options : { } ,
3849 } , baseModule ) ;
3950 } ) ;
4051
52+ afterEach ( ( ) => {
53+ sandbox . restore ( ) ;
54+ } ) ;
55+
4156 it ( 'should expose a `validate` method' , ( ) => {
4257 expect ( module . validate ) . to . be . a ( 'function' ) ;
4358 } ) ;
@@ -266,6 +281,12 @@ describe('validate', () => {
266281 } ) ;
267282
268283 describe ( 'entries' , ( ) => {
284+ let globSyncStub ;
285+
286+ beforeEach ( ( ) => {
287+ globSyncStub = sandbox . stub ( globMock , 'sync' ) ;
288+ } ) ;
289+
269290 const testFunctionsConfig = {
270291 func1 : {
271292 handler : 'module1.func1handler' ,
@@ -305,7 +326,7 @@ describe('validate', () => {
305326 } ,
306327 } ;
307328
308- it ( 'should expose entries from serverless.yml if `options.function` is not defined' , ( ) => {
329+ it ( 'should expose all functions if `options.function` is not defined' , ( ) => {
309330 const testOutPath = 'test' ;
310331 const testConfig = {
311332 entry : 'test' ,
@@ -316,22 +337,24 @@ describe('validate', () => {
316337 } ;
317338 module . serverless . service . custom . webpack = testConfig ;
318339 module . serverless . service . functions = testFunctionsConfig ;
319- return module
320- . validate ( )
321- . then ( ( ) => {
322- const lib = require ( '../lib/index' ) ;
323- const expectedLibEntries = {
324- 'module1.js' : './module1.js' ,
325- 'module2.js' : './module2.js' ,
326- 'handlers/func3/module2.js' : './handlers/func3/module2.js' ,
327- 'handlers/module2/func3/module2.js' : './handlers/module2/func3/module2.js' ,
328- } ;
329-
330- expect ( lib . entries ) . to . deep . eq ( expectedLibEntries )
331- } ) ;
340+ globSyncStub . callsFake ( filename => [ _ . replace ( filename , '*' , 'js' ) ] ) ;
341+ return expect ( module . validate ( ) ) . to . be . fulfilled
342+ . then ( ( ) => {
343+ const lib = require ( '../lib/index' ) ;
344+ const expectedLibEntries = {
345+ 'module1' : './module1.js' ,
346+ 'module2' : './module2.js' ,
347+ 'handlers/func3/module2' : './handlers/func3/module2.js' ,
348+ 'handlers/module2/func3/module2' : './handlers/module2/func3/module2.js' ,
349+ } ;
350+
351+ expect ( lib . entries ) . to . deep . equal ( expectedLibEntries ) ;
352+ expect ( globSyncStub ) . to . have . callCount ( 4 ) ;
353+ expect ( serverless . cli . log ) . to . not . have . been . called ;
354+ } ) ;
332355 } ) ;
333356
334- it ( 'should expose entries with `options. function` value if `options.function` is defined and found in entries from serverless.yml ' , ( ) => {
357+ it ( 'should expose the requested function if `options.function` is defined and the function is found ' , ( ) => {
335358 const testOutPath = 'test' ;
336359 const testFunction = 'func1' ;
337360 const testConfig = {
@@ -344,16 +367,97 @@ describe('validate', () => {
344367 module . serverless . service . custom . webpack = testConfig ;
345368 module . serverless . service . functions = testFunctionsConfig ;
346369 module . options . function = testFunction ;
347- return module
348- . validate ( )
349- . then ( ( ) => {
350- const lib = require ( '../lib/index' ) ;
351- const expectedLibEntries = {
352- 'module1.js' : './module1.js'
353- } ;
354-
355- expect ( lib . entries ) . to . deep . eq ( expectedLibEntries )
356- } ) ;
370+ globSyncStub . callsFake ( filename => [ _ . replace ( filename , '*' , 'js' ) ] ) ;
371+ return expect ( module . validate ( ) ) . to . be . fulfilled
372+ . then ( ( ) => {
373+ const lib = require ( '../lib/index' ) ;
374+ const expectedLibEntries = {
375+ 'module1' : './module1.js'
376+ } ;
377+
378+ expect ( lib . entries ) . to . deep . equal ( expectedLibEntries )
379+ expect ( globSyncStub ) . to . have . been . calledOnce ;
380+ expect ( serverless . cli . log ) . to . not . have . been . called ;
381+ } ) ;
382+ } ) ;
383+
384+ it ( 'should show a warning if more than one matching handler is found' , ( ) => {
385+ const testOutPath = 'test' ;
386+ const testFunction = 'func1' ;
387+ const testConfig = {
388+ entry : 'test' ,
389+ context : 'testcontext' ,
390+ output : {
391+ path : testOutPath ,
392+ } ,
393+ } ;
394+ module . serverless . service . custom . webpack = testConfig ;
395+ module . serverless . service . functions = testFunctionsConfig ;
396+ module . options . function = testFunction ;
397+ globSyncStub . returns ( [ 'module1.ts' , 'module1.js' ] ) ;
398+ return expect ( module . validate ( ) ) . to . be . fulfilled
399+ . then ( ( ) => {
400+ const lib = require ( '../lib/index' ) ;
401+ const expectedLibEntries = {
402+ 'module1' : './module1.ts'
403+ } ;
404+
405+ expect ( lib . entries ) . to . deep . equal ( expectedLibEntries )
406+ expect ( globSyncStub ) . to . have . been . calledOnce ;
407+ expect ( serverless . cli . log ) . to . have . been . calledOnce ;
408+ expect ( serverless . cli . log ) . to . have . been . calledWith (
409+ 'WARNING: More than one matching handlers found for \'module1\'. Using \'module1.ts\'.'
410+ ) ;
411+ } ) ;
412+ } ) ;
413+
414+ it ( 'should select the most probable handler if multiple hits are found' , ( ) => {
415+ const testOutPath = 'test' ;
416+ const testFunction = 'func1' ;
417+ const testConfig = {
418+ entry : 'test' ,
419+ context : 'testcontext' ,
420+ output : {
421+ path : testOutPath ,
422+ } ,
423+ } ;
424+ module . serverless . service . custom . webpack = testConfig ;
425+ module . serverless . service . functions = testFunctionsConfig ;
426+ module . options . function = testFunction ;
427+ globSyncStub . returns ( [ 'module1.doc' , 'module1.json' , 'module1.test.js' , 'module1.ts' , 'module1.js' ] ) ;
428+ return expect ( module . validate ( ) ) . to . be . fulfilled
429+ . then ( ( ) => {
430+ const lib = require ( '../lib/index' ) ;
431+ const expectedLibEntries = {
432+ 'module1' : './module1.ts'
433+ } ;
434+
435+ expect ( lib . entries ) . to . deep . equal ( expectedLibEntries )
436+ expect ( globSyncStub ) . to . have . been . calledOnce ;
437+ expect ( serverless . cli . log ) . to . have . been . calledOnce ;
438+ expect ( serverless . cli . log ) . to . have . been . calledWith (
439+ 'WARNING: More than one matching handlers found for \'module1\'. Using \'module1.ts\'.'
440+ ) ;
441+ } ) ;
442+ } ) ;
443+
444+ it ( 'should throw an exception if no handler is found' , ( ) => {
445+ const testOutPath = 'test' ;
446+ const testFunction = 'func1' ;
447+ const testConfig = {
448+ entry : 'test' ,
449+ context : 'testcontext' ,
450+ output : {
451+ path : testOutPath ,
452+ } ,
453+ } ;
454+ module . serverless . service . custom . webpack = testConfig ;
455+ module . serverless . service . functions = testFunctionsConfig ;
456+ module . options . function = testFunction ;
457+ globSyncStub . returns ( [ ] ) ;
458+ expect ( ( ) => {
459+ module . validate ( ) ;
460+ } ) . to . throw ( / N o m a t c h i n g h a n d l e r f o u n d f o r / ) ;
357461 } ) ;
358462
359463 it ( 'should throw an exception if `options.function` is defined but not found in entries from serverless.yml' , ( ) => {
0 commit comments