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