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