@@ -12,6 +12,7 @@ import { OptionType } from "../lib/common/enums";
1212import * as _ from "lodash" ;
1313
1414let isExecutionStopped = false ;
15+ let warnings : string [ ] = [ ] ;
1516
1617function createTestInjector ( ) : IInjector {
1718 const testInjector = new Yok ( ) ;
@@ -23,6 +24,11 @@ function createTestInjector(): IInjector {
2324 setSettings : ( settings : IConfigurationSettings ) : any => undefined ,
2425 getProfileDir : ( ) => "profileDir" ,
2526 } ) ;
27+ testInjector . register ( "logger" , {
28+ warn : ( message : string ) : void => {
29+ warnings . push ( message ) ;
30+ } ,
31+ } ) ;
2632
2733 return testInjector ;
2834}
@@ -32,8 +38,7 @@ function createOptions(testInjector: IInjector): IOptions {
3238 return options ;
3339}
3440
35- // TODO: Igor and Nathan will make this work again
36- describe . skip ( "options" , ( ) => {
41+ describe ( "options" , ( ) => {
3742 let testInjector : IInjector ;
3843 beforeEach ( ( ) => {
3944 testInjector = createTestInjector ( ) ;
@@ -48,6 +53,14 @@ describe.skip("options", () => {
4853
4954 testInjector . register ( "errors" , errors ) ;
5055 isExecutionStopped = false ;
56+ warnings = [ ] ;
57+ // The assertions below describe the hard-fail behavior, which is opt-in
58+ // while validation is staged. The staging itself is covered separately.
59+ process . env . NS_STRICT_OPTIONS = "error" ;
60+ } ) ;
61+
62+ afterEach ( ( ) => {
63+ delete process . env . NS_STRICT_OPTIONS ;
5164 } ) ;
5265
5366 describe ( "validateOptions" , ( ) => {
@@ -180,13 +193,13 @@ describe.skip("options", () => {
180193
181194 it ( "converts string value to array when option type is array" , ( ) => {
182195 const options : any = createOptions ( testInjector ) ;
183- process . argv . push ( "--config " ) ;
196+ process . argv . push ( "--test1 " ) ;
184197 process . argv . push ( "value" ) ;
185198 options . validateOptions ( { test1 : { type : OptionType . Array } } ) ;
186199 process . argv . pop ( ) ;
187200 process . argv . pop ( ) ;
188201 assert . isFalse ( isExecutionStopped ) ;
189- assert . deepStrictEqual ( [ "value" ] , < any > options [ "config" ] ) ;
202+ assert . deepStrictEqual ( [ "value" ] , < any > options . argv . test1 ) ;
190203 } ) ;
191204
192205 it ( "does not break execution when valid commandSpecificOptions are passed" , ( ) => {
@@ -306,6 +319,91 @@ describe.skip("options", () => {
306319 "Dashed options (special-dashed-v) are added to yargs.argv in two ways: special-dashed-v and specialDashedV" ,
307320 ) ;
308321 } ) ;
322+
323+ // vision-ng and friends are declared with a literal dashed key, so the
324+ // camelCase spelling yargs derives has no declaration of its own.
325+ _ . each ( [ "--vision-ng" , "--visionNg" ] , ( arg ) => {
326+ it ( `does not break execution when ${ arg } is passed` , ( ) => {
327+ process . argv . push ( arg ) ;
328+ const options = createOptions ( testInjector ) ;
329+ options . validateOptions ( ) ;
330+ process . argv . pop ( ) ;
331+ assert . isFalse ( isExecutionStopped ) ;
332+ assert . isEmpty ( warnings ) ;
333+ } ) ;
334+ } ) ;
335+ } ) ;
336+
337+ describe ( "does not report valid options" , ( ) => {
338+ it ( "accepts a negated declared boolean" , ( ) => {
339+ process . argv . push ( "--no-hmr" ) ;
340+ const options = createOptions ( testInjector ) ;
341+ options . validateOptions ( ) ;
342+ process . argv . pop ( ) ;
343+ assert . isFalse ( isExecutionStopped ) ;
344+ assert . isEmpty ( warnings ) ;
345+ assert . isFalse ( < boolean > options . argv . hmr ) ;
346+ } ) ;
347+
348+ it ( "accepts dot-notation values of an object option" , ( ) => {
349+ process . argv . push ( "--env.production" ) ;
350+ process . argv . push ( "--env.sourceMap" ) ;
351+ const options = createOptions ( testInjector ) ;
352+ options . validateOptions ( ) ;
353+ process . argv . pop ( ) ;
354+ process . argv . pop ( ) ;
355+ assert . isFalse ( isExecutionStopped ) ;
356+ assert . isEmpty ( warnings ) ;
357+ assert . deepStrictEqual ( options . argv . env , {
358+ production : true ,
359+ sourceMap : true ,
360+ } ) ;
361+ } ) ;
362+ } ) ;
363+
364+ describe ( "staged reporting" , ( ) => {
365+ it ( "warns instead of failing when an option is not supported" , ( ) => {
366+ delete process . env . NS_STRICT_OPTIONS ;
367+ process . argv . push ( "--unknownOption" ) ;
368+ const options = createOptions ( testInjector ) ;
369+ options . validateOptions ( ) ;
370+ process . argv . pop ( ) ;
371+ assert . isFalse ( isExecutionStopped ) ;
372+ assert . lengthOf ( warnings , 1 ) ;
373+ assert . include ( warnings [ 0 ] , "'unknownOption' is not supported" ) ;
374+ assert . include ( warnings [ 0 ] , "NS_STRICT_OPTIONS=error" ) ;
375+ } ) ;
376+
377+ it ( "fails when an option is not supported and NS_STRICT_OPTIONS=error" , ( ) => {
378+ process . env . NS_STRICT_OPTIONS = "error" ;
379+ process . argv . push ( "--unknownOption" ) ;
380+ const options = createOptions ( testInjector ) ;
381+ options . validateOptions ( ) ;
382+ process . argv . pop ( ) ;
383+ assert . isTrue ( isExecutionStopped ) ;
384+ assert . isEmpty ( warnings ) ;
385+ } ) ;
386+
387+ it ( "warns instead of failing when a string option has no value" , ( ) => {
388+ delete process . env . NS_STRICT_OPTIONS ;
389+ process . argv . push ( "--path" ) ;
390+ const options = createOptions ( testInjector ) ;
391+ options . validateOptions ( ) ;
392+ process . argv . pop ( ) ;
393+ assert . isFalse ( isExecutionStopped ) ;
394+ assert . lengthOf ( warnings , 1 ) ;
395+ assert . include ( warnings [ 0 ] , "'path' requires non-empty value" ) ;
396+ } ) ;
397+
398+ it ( "reports an undeclared negated flag under the spelling that was used" , ( ) => {
399+ delete process . env . NS_STRICT_OPTIONS ;
400+ process . argv . push ( "--no-something" ) ;
401+ const options = createOptions ( testInjector ) ;
402+ options . validateOptions ( ) ;
403+ process . argv . pop ( ) ;
404+ assert . lengthOf ( warnings , 1 ) ;
405+ assert . include ( warnings [ 0 ] , "'no-something' is not supported" ) ;
406+ } ) ;
309407 } ) ;
310408 } ) ;
311409
0 commit comments