1
1
import { expect } from 'chai' ;
2
2
import { describe , it } from 'mocha' ;
3
3
4
+ import type { ObjMap } from '../../jsutils/ObjMap' ;
4
5
import { invariant } from '../../jsutils/invariant' ;
6
+ import { identityFunc } from '../../jsutils/identityFunc' ;
7
+
8
+ import { print } from '../../language/printer' ;
9
+ import { parseValue } from '../../language/parser' ;
5
10
6
11
import type { GraphQLInputType } from '../../type/definition' ;
7
- import { GraphQLInt } from '../../type/scalars' ;
12
+ import {
13
+ GraphQLInt ,
14
+ GraphQLFloat ,
15
+ GraphQLString ,
16
+ GraphQLBoolean ,
17
+ GraphQLID ,
18
+ } from '../../type/scalars' ;
8
19
import {
9
20
GraphQLList ,
10
21
GraphQLNonNull ,
@@ -13,7 +24,7 @@ import {
13
24
GraphQLInputObjectType ,
14
25
} from '../../type/definition' ;
15
26
16
- import { coerceInputValue } from '../coerceInputValue' ;
27
+ import { coerceInputValue , coerceInputLiteral } from '../coerceInputValue' ;
17
28
18
29
type CoerceResult = { |
19
30
value : mixed ,
@@ -425,3 +436,239 @@ describe('coerceInputValue', () => {
425
436
} ) ;
426
437
} ) ;
427
438
} ) ;
439
+
440
+ describe ( 'coerceInputLiteral' , ( ) => {
441
+ function test ( valueText : string , type : GraphQLInputType , expected : mixed ) {
442
+ return testWithVariables ( undefined , valueText , type , expected ) ;
443
+ }
444
+
445
+ function testWithVariables (
446
+ variables : ?ObjMap < mixed > ,
447
+ valueText : string ,
448
+ type : GraphQLInputType ,
449
+ expected : mixed ,
450
+ ) {
451
+ const ast = parseValue ( valueText ) ;
452
+ const value = coerceInputLiteral ( ast , type , variables ) ;
453
+ return expect ( value ) . to . deep . equal ( expected ) ;
454
+ }
455
+
456
+ it ( 'converts according to input coercion rules' , ( ) => {
457
+ test ( 'true' , GraphQLBoolean , true ) ;
458
+ test ( 'false' , GraphQLBoolean , false ) ;
459
+ test ( '123' , GraphQLInt , 123 ) ;
460
+ test ( '123' , GraphQLFloat , 123 ) ;
461
+ test ( '123.456' , GraphQLFloat , 123.456 ) ;
462
+ test ( '"abc123"' , GraphQLString , 'abc123' ) ;
463
+ test ( '123456' , GraphQLID , '123456' ) ;
464
+ test ( '"123456"' , GraphQLID , '123456' ) ;
465
+ } ) ;
466
+
467
+ it ( 'does not convert when input coercion rules reject a value' , ( ) => {
468
+ test ( '123' , GraphQLBoolean , undefined ) ;
469
+ test ( '123.456' , GraphQLInt , undefined ) ;
470
+ test ( 'true' , GraphQLInt , undefined ) ;
471
+ test ( '"123"' , GraphQLInt , undefined ) ;
472
+ test ( '"123"' , GraphQLFloat , undefined ) ;
473
+ test ( '123' , GraphQLString , undefined ) ;
474
+ test ( 'true' , GraphQLString , undefined ) ;
475
+ test ( '123.456' , GraphQLString , undefined ) ;
476
+ test ( '123.456' , GraphQLID , undefined ) ;
477
+ } ) ;
478
+
479
+ it ( 'convert using parseLiteral from a custom scalar type' , ( ) => {
480
+ const passthroughScalar = new GraphQLScalarType ( {
481
+ name : 'PassthroughScalar' ,
482
+ parseLiteral ( node ) {
483
+ invariant ( node . kind === 'StringValue' ) ;
484
+ return node . value ;
485
+ } ,
486
+ parseValue : identityFunc ,
487
+ } ) ;
488
+
489
+ test ( '"value"' , passthroughScalar , 'value' ) ;
490
+
491
+ const printScalar = new GraphQLScalarType ( {
492
+ name : 'PrintScalar' ,
493
+ parseLiteral ( node ) {
494
+ return `~~~${ print ( node ) } ~~~` ;
495
+ } ,
496
+ parseValue : identityFunc ,
497
+ } ) ;
498
+
499
+ test ( '"value"' , printScalar , '~~~"value"~~~' ) ;
500
+
501
+ const throwScalar = new GraphQLScalarType ( {
502
+ name : 'ThrowScalar' ,
503
+ parseLiteral ( ) {
504
+ throw new Error ( 'Test' ) ;
505
+ } ,
506
+ parseValue : identityFunc ,
507
+ } ) ;
508
+
509
+ test ( 'value' , throwScalar , undefined ) ;
510
+
511
+ const returnUndefinedScalar = new GraphQLScalarType ( {
512
+ name : 'ReturnUndefinedScalar' ,
513
+ parseLiteral ( ) {
514
+ return undefined ;
515
+ } ,
516
+ parseValue : identityFunc ,
517
+ } ) ;
518
+
519
+ test ( 'value' , returnUndefinedScalar , undefined ) ;
520
+ } ) ;
521
+
522
+ it ( 'converts enum values according to input coercion rules' , ( ) => {
523
+ const testEnum = new GraphQLEnumType ( {
524
+ name : 'TestColor' ,
525
+ values : {
526
+ RED : { value : 1 } ,
527
+ GREEN : { value : 2 } ,
528
+ BLUE : { value : 3 } ,
529
+ NULL : { value : null } ,
530
+ NAN : { value : NaN } ,
531
+ NO_CUSTOM_VALUE : { value : undefined } ,
532
+ } ,
533
+ } ) ;
534
+
535
+ test ( 'RED' , testEnum , 1 ) ;
536
+ test ( 'BLUE' , testEnum , 3 ) ;
537
+ test ( '3' , testEnum , undefined ) ;
538
+ test ( '"BLUE"' , testEnum , undefined ) ;
539
+ test ( 'null' , testEnum , null ) ;
540
+ test ( 'NULL' , testEnum , null ) ;
541
+ test ( 'NULL' , new GraphQLNonNull ( testEnum ) , null ) ;
542
+ test ( 'NAN' , testEnum , NaN ) ;
543
+ test ( 'NO_CUSTOM_VALUE' , testEnum , 'NO_CUSTOM_VALUE' ) ;
544
+ } ) ;
545
+
546
+ // Boolean!
547
+ const nonNullBool = new GraphQLNonNull ( GraphQLBoolean ) ;
548
+ // [Boolean]
549
+ const listOfBool = new GraphQLList ( GraphQLBoolean ) ;
550
+ // [Boolean!]
551
+ const listOfNonNullBool = new GraphQLList ( nonNullBool ) ;
552
+ // [Boolean]!
553
+ const nonNullListOfBool = new GraphQLNonNull ( listOfBool ) ;
554
+ // [Boolean!]!
555
+ const nonNullListOfNonNullBool = new GraphQLNonNull ( listOfNonNullBool ) ;
556
+
557
+ it ( 'coerces to null unless non-null' , ( ) => {
558
+ test ( 'null' , GraphQLBoolean , null ) ;
559
+ test ( 'null' , nonNullBool , undefined ) ;
560
+ } ) ;
561
+
562
+ it ( 'coerces lists of values' , ( ) => {
563
+ test ( 'true' , listOfBool , [ true ] ) ;
564
+ test ( '123' , listOfBool , undefined ) ;
565
+ test ( 'null' , listOfBool , null ) ;
566
+ test ( '[true, false]' , listOfBool , [ true , false ] ) ;
567
+ test ( '[true, 123]' , listOfBool , undefined ) ;
568
+ test ( '[true, null]' , listOfBool , [ true , null ] ) ;
569
+ test ( '{ true: true }' , listOfBool , undefined ) ;
570
+ } ) ;
571
+
572
+ it ( 'coerces non-null lists of values' , ( ) => {
573
+ test ( 'true' , nonNullListOfBool , [ true ] ) ;
574
+ test ( '123' , nonNullListOfBool ) . to . equal ( undefined ) ;
575
+ test ( 'null' , nonNullListOfBool ) . to . equal ( undefined ) ;
576
+ test ( '[true, false]' , nonNullListOfBool , [ true , false ] ) ;
577
+ test ( '[true, 123]' , nonNullListOfBool , undefined ) ;
578
+ test ( '[true, null]' , nonNullListOfBool , [ true , null ] ) ;
579
+ } ) ;
580
+
581
+ it ( 'coerces lists of non-null values' , ( ) => {
582
+ test ( 'true' , listOfNonNullBool , [ true ] ) ;
583
+ test ( '123' , listOfNonNullBool , undefined ) ;
584
+ test ( 'null' , listOfNonNullBool , null ) ;
585
+ test ( '[true, false]' , listOfNonNullBool , [ true , false ] ) ;
586
+ test ( '[true, 123]' , listOfNonNullBool , undefined ) ;
587
+ test ( '[true, null]' , listOfNonNullBool , undefined ) ;
588
+ } ) ;
589
+
590
+ it ( 'coerces non-null lists of non-null values' , ( ) => {
591
+ test ( 'true' , nonNullListOfNonNullBool , [ true ] ) ;
592
+ test ( '123' , nonNullListOfNonNullBool , undefined ) ;
593
+ test ( 'null' , nonNullListOfNonNullBool , undefined ) ;
594
+ test ( '[true, false]' , nonNullListOfNonNullBool , [ true , false ] ) ;
595
+ test ( '[true, 123]' , nonNullListOfNonNullBool , undefined ) ;
596
+ test ( '[true, null]' , nonNullListOfNonNullBool , undefined ) ;
597
+ } ) ;
598
+
599
+ it ( 'uses default values for unprovided fields' , ( ) => {
600
+ const type = new GraphQLInputObjectType ( {
601
+ name : 'TestInput' ,
602
+ fields : {
603
+ int : { type : GraphQLInt , defaultValue : 42 } ,
604
+ } ,
605
+ } ) ;
606
+
607
+ test ( '{}' , type , { int : 42 } ) ;
608
+ } ) ;
609
+
610
+ const testInputObj = new GraphQLInputObjectType ( {
611
+ name : 'TestInput' ,
612
+ fields : {
613
+ int : { type : GraphQLInt , defaultValue : 42 } ,
614
+ bool : { type : GraphQLBoolean } ,
615
+ requiredBool : { type : nonNullBool } ,
616
+ } ,
617
+ } ) ;
618
+
619
+ it ( 'coerces input objects according to input coercion rules' , ( ) => {
620
+ test ( 'null' , testInputObj , null ) ;
621
+ test ( '123' , testInputObj , undefined ) ;
622
+ test ( '[]' , testInputObj , undefined ) ;
623
+ test ( '{ requiredBool: true }' , testInputObj , {
624
+ int : 42 ,
625
+ requiredBool : true ,
626
+ } ) ;
627
+ test ( '{ int: null, requiredBool: true }' , testInputObj , {
628
+ int : null ,
629
+ requiredBool : true ,
630
+ } ) ;
631
+ test ( '{ int: 123, requiredBool: false }' , testInputObj , {
632
+ int : 123 ,
633
+ requiredBool : false ,
634
+ } ) ;
635
+ test ( '{ bool: true, requiredBool: false }' , testInputObj , {
636
+ int : 42 ,
637
+ bool : true ,
638
+ requiredBool : false ,
639
+ } ) ;
640
+ test ( '{ int: true, requiredBool: true }' , testInputObj , undefined ) ;
641
+ test ( '{ requiredBool: null }' , testInputObj , undefined ) ;
642
+ test ( '{ bool: true }' , testInputObj , undefined ) ;
643
+ test ( '{ requiredBool: true, unknown: 123 }' , testInputObj , undefined ) ;
644
+ } ) ;
645
+
646
+ it ( 'accepts variable values assuming already coerced' , ( ) => {
647
+ test ( '$var' , GraphQLBoolean , undefined ) ;
648
+ testWithVariables ( { var : true } , '$var' , GraphQLBoolean , true ) ;
649
+ testWithVariables ( { var : null } , '$var' , GraphQLBoolean , null ) ;
650
+ testWithVariables ( { var : null } , '$var' , nonNullBool , undefined ) ;
651
+ } ) ;
652
+
653
+ it ( 'asserts variables are provided as items in lists' , ( ) => {
654
+ test ( '[ $foo ]' , listOfBool , [ null ] ) ;
655
+ test ( '[ $foo ]' , listOfNonNullBool , undefined ) ;
656
+ testWithVariables ( { foo : true } , '[ $foo ]' , listOfNonNullBool , [ true ] ) ;
657
+ // Note: variables are expected to have already been coerced, so we
658
+ // do not expect the singleton wrapping behavior for variables.
659
+ testWithVariables ( { foo : true } , '$foo' , listOfNonNullBool , true ) ;
660
+ testWithVariables ( { foo : [ true ] } , '$foo' , listOfNonNullBool , [ true ] ) ;
661
+ } ) ;
662
+
663
+ it ( 'omits input object fields for unprovided variables' , ( ) => {
664
+ test ( '{ int: $foo, bool: $foo, requiredBool: true }' , testInputObj , {
665
+ int : 42 ,
666
+ requiredBool : true ,
667
+ } ) ;
668
+ test ( '{ requiredBool: $foo }' , testInputObj , undefined ) ;
669
+ testWithVariables ( { foo : true } , '{ requiredBool: $foo }' , testInputObj , {
670
+ int : 42 ,
671
+ requiredBool : true ,
672
+ } ) ;
673
+ } ) ;
674
+ } ) ;
0 commit comments