33import { expect } from 'chai' ;
44import { describe , it } from 'mocha' ;
55
6+ import type { ObjMap } from '../../jsutils/ObjMap' ;
7+ import { invariant } from '../../jsutils/invariant' ;
8+ import { identityFunc } from '../../jsutils/identityFunc' ;
9+
610import { parseValue } from '../../language/parser' ;
7- import { GraphQLBoolean } from '../../type/scalars' ;
11+
12+ import type { GraphQLInputType } from '../../type/definition' ;
13+ import {
14+ GraphQLInt ,
15+ GraphQLFloat ,
16+ GraphQLString ,
17+ GraphQLBoolean ,
18+ GraphQLID ,
19+ } from '../../type/scalars' ;
20+ import {
21+ GraphQLList ,
22+ GraphQLNonNull ,
23+ GraphQLScalarType ,
24+ GraphQLEnumType ,
25+ GraphQLInputObjectType ,
26+ } from '../../type/definition' ;
27+
828import { valueFromAST } from '../valueFromAST' ;
929
1030import { expectWarning } from './expectWarning' ;
1131
1232describe ( 'valueFromAST' , ( ) => {
33+ function expectValueFrom (
34+ valueText : string ,
35+ type : GraphQLInputType ,
36+ variables ?: ObjMap < mixed > ,
37+ ) {
38+ const ast = parseValue ( valueText ) ;
39+ const value = valueFromAST ( ast , type , variables ) ;
40+ return expect ( value ) ;
41+ }
42+
1343 it ( 'warns about deprecation' , ( ) => {
1444 expectWarning ( ( ) =>
1545 valueFromAST ( parseValue ( 'true' ) , GraphQLBoolean ) ,
@@ -21,4 +51,227 @@ describe('valueFromAST', () => {
2151 it ( 'rejects empty input' , ( ) => {
2252 expect ( valueFromAST ( null , GraphQLBoolean ) ) . to . deep . equal ( undefined ) ;
2353 } ) ;
54+
55+ it ( 'converts according to input coercion rules' , ( ) => {
56+ expectValueFrom ( 'true' , GraphQLBoolean ) . to . equal ( true ) ;
57+ expectValueFrom ( 'false' , GraphQLBoolean ) . to . equal ( false ) ;
58+ expectValueFrom ( '123' , GraphQLInt ) . to . equal ( 123 ) ;
59+ expectValueFrom ( '123' , GraphQLFloat ) . to . equal ( 123 ) ;
60+ expectValueFrom ( '123.456' , GraphQLFloat ) . to . equal ( 123.456 ) ;
61+ expectValueFrom ( '"abc123"' , GraphQLString ) . to . equal ( 'abc123' ) ;
62+ expectValueFrom ( '123456' , GraphQLID ) . to . equal ( '123456' ) ;
63+ expectValueFrom ( '"123456"' , GraphQLID ) . to . equal ( '123456' ) ;
64+ } ) ;
65+
66+ it ( 'does not convert when input coercion rules reject a value' , ( ) => {
67+ expectValueFrom ( '123' , GraphQLBoolean ) . to . equal ( undefined ) ;
68+ expectValueFrom ( '123.456' , GraphQLInt ) . to . equal ( undefined ) ;
69+ expectValueFrom ( 'true' , GraphQLInt ) . to . equal ( undefined ) ;
70+ expectValueFrom ( '"123"' , GraphQLInt ) . to . equal ( undefined ) ;
71+ expectValueFrom ( '"123"' , GraphQLFloat ) . to . equal ( undefined ) ;
72+ expectValueFrom ( '123' , GraphQLString ) . to . equal ( undefined ) ;
73+ expectValueFrom ( 'true' , GraphQLString ) . to . equal ( undefined ) ;
74+ expectValueFrom ( '123.456' , GraphQLString ) . to . equal ( undefined ) ;
75+ } ) ;
76+
77+ it ( 'convert using parseLiteral from a custom scalar type' , ( ) => {
78+ const passthroughScalar = new GraphQLScalarType ( {
79+ name : 'PassthroughScalar' ,
80+ parseLiteral ( node ) {
81+ invariant ( node . kind === 'StringValue' ) ;
82+ return node . value ;
83+ } ,
84+ parseValue : identityFunc ,
85+ } ) ;
86+
87+ expectValueFrom ( '"value"' , passthroughScalar ) . to . equal ( 'value' ) ;
88+
89+ const throwScalar = new GraphQLScalarType ( {
90+ name : 'ThrowScalar' ,
91+ parseLiteral ( ) {
92+ throw new Error ( 'Test' ) ;
93+ } ,
94+ parseValue : identityFunc ,
95+ } ) ;
96+
97+ expectValueFrom ( 'value' , throwScalar ) . to . equal ( undefined ) ;
98+
99+ const returnUndefinedScalar = new GraphQLScalarType ( {
100+ name : 'ReturnUndefinedScalar' ,
101+ parseLiteral ( ) {
102+ return undefined ;
103+ } ,
104+ parseValue : identityFunc ,
105+ } ) ;
106+
107+ expectValueFrom ( 'value' , returnUndefinedScalar ) . to . equal ( undefined ) ;
108+ } ) ;
109+
110+ it ( 'converts enum values according to input coercion rules' , ( ) => {
111+ const testEnum = new GraphQLEnumType ( {
112+ name : 'TestColor' ,
113+ values : {
114+ RED : { value : 1 } ,
115+ GREEN : { value : 2 } ,
116+ BLUE : { value : 3 } ,
117+ NULL : { value : null } ,
118+ NAN : { value : NaN } ,
119+ NO_CUSTOM_VALUE : { value : undefined } ,
120+ } ,
121+ } ) ;
122+
123+ expectValueFrom ( 'RED' , testEnum ) . to . equal ( 1 ) ;
124+ expectValueFrom ( 'BLUE' , testEnum ) . to . equal ( 3 ) ;
125+ expectValueFrom ( '3' , testEnum ) . to . equal ( undefined ) ;
126+ expectValueFrom ( '"BLUE"' , testEnum ) . to . equal ( undefined ) ;
127+ expectValueFrom ( 'null' , testEnum ) . to . equal ( null ) ;
128+ expectValueFrom ( 'NULL' , testEnum ) . to . equal ( null ) ;
129+ expectValueFrom ( 'NULL' , new GraphQLNonNull ( testEnum ) ) . to . equal ( null ) ;
130+ expectValueFrom ( 'NAN' , testEnum ) . to . deep . equal ( NaN ) ;
131+ expectValueFrom ( 'NO_CUSTOM_VALUE' , testEnum ) . to . equal ( 'NO_CUSTOM_VALUE' ) ;
132+ } ) ;
133+
134+ // Boolean!
135+ const nonNullBool = new GraphQLNonNull ( GraphQLBoolean ) ;
136+ // [Boolean]
137+ const listOfBool = new GraphQLList ( GraphQLBoolean ) ;
138+ // [Boolean!]
139+ const listOfNonNullBool = new GraphQLList ( nonNullBool ) ;
140+ // [Boolean]!
141+ const nonNullListOfBool = new GraphQLNonNull ( listOfBool ) ;
142+ // [Boolean!]!
143+ const nonNullListOfNonNullBool = new GraphQLNonNull ( listOfNonNullBool ) ;
144+
145+ it ( 'coerces to null unless non-null' , ( ) => {
146+ expectValueFrom ( 'null' , GraphQLBoolean ) . to . equal ( null ) ;
147+ expectValueFrom ( 'null' , nonNullBool ) . to . equal ( undefined ) ;
148+ } ) ;
149+
150+ it ( 'coerces lists of values' , ( ) => {
151+ expectValueFrom ( 'true' , listOfBool ) . to . deep . equal ( [ true ] ) ;
152+ expectValueFrom ( '123' , listOfBool ) . to . equal ( undefined ) ;
153+ expectValueFrom ( 'null' , listOfBool ) . to . equal ( null ) ;
154+ expectValueFrom ( '[true, false]' , listOfBool ) . to . deep . equal ( [ true , false ] ) ;
155+ expectValueFrom ( '[true, 123]' , listOfBool ) . to . equal ( undefined ) ;
156+ expectValueFrom ( '[true, null]' , listOfBool ) . to . deep . equal ( [ true , null ] ) ;
157+ expectValueFrom ( '{ true: true }' , listOfBool ) . to . equal ( undefined ) ;
158+ } ) ;
159+
160+ it ( 'coerces non-null lists of values' , ( ) => {
161+ expectValueFrom ( 'true' , nonNullListOfBool ) . to . deep . equal ( [ true ] ) ;
162+ expectValueFrom ( '123' , nonNullListOfBool ) . to . equal ( undefined ) ;
163+ expectValueFrom ( 'null' , nonNullListOfBool ) . to . equal ( undefined ) ;
164+ expectValueFrom ( '[true, false]' , nonNullListOfBool ) . to . deep . equal ( [
165+ true ,
166+ false ,
167+ ] ) ;
168+ expectValueFrom ( '[true, 123]' , nonNullListOfBool ) . to . equal ( undefined ) ;
169+ expectValueFrom ( '[true, null]' , nonNullListOfBool ) . to . deep . equal ( [
170+ true ,
171+ null ,
172+ ] ) ;
173+ } ) ;
174+
175+ it ( 'coerces lists of non-null values' , ( ) => {
176+ expectValueFrom ( 'true' , listOfNonNullBool ) . to . deep . equal ( [ true ] ) ;
177+ expectValueFrom ( '123' , listOfNonNullBool ) . to . equal ( undefined ) ;
178+ expectValueFrom ( 'null' , listOfNonNullBool ) . to . equal ( null ) ;
179+ expectValueFrom ( '[true, false]' , listOfNonNullBool ) . to . deep . equal ( [
180+ true ,
181+ false ,
182+ ] ) ;
183+ expectValueFrom ( '[true, 123]' , listOfNonNullBool ) . to . equal ( undefined ) ;
184+ expectValueFrom ( '[true, null]' , listOfNonNullBool ) . to . equal ( undefined ) ;
185+ } ) ;
186+
187+ it ( 'coerces non-null lists of non-null values' , ( ) => {
188+ expectValueFrom ( 'true' , nonNullListOfNonNullBool ) . to . deep . equal ( [ true ] ) ;
189+ expectValueFrom ( '123' , nonNullListOfNonNullBool ) . to . equal ( undefined ) ;
190+ expectValueFrom ( 'null' , nonNullListOfNonNullBool ) . to . equal ( undefined ) ;
191+ expectValueFrom ( '[true, false]' , nonNullListOfNonNullBool ) . to . deep . equal ( [
192+ true ,
193+ false ,
194+ ] ) ;
195+ expectValueFrom ( '[true, 123]' , nonNullListOfNonNullBool ) . to . equal (
196+ undefined ,
197+ ) ;
198+ expectValueFrom ( '[true, null]' , nonNullListOfNonNullBool ) . to . equal (
199+ undefined ,
200+ ) ;
201+ } ) ;
202+
203+ const testInputObj = new GraphQLInputObjectType ( {
204+ name : 'TestInput' ,
205+ fields : {
206+ int : { type : GraphQLInt , defaultValue : 42 } ,
207+ bool : { type : GraphQLBoolean } ,
208+ requiredBool : { type : nonNullBool } ,
209+ } ,
210+ } ) ;
211+
212+ it ( 'coerces input objects according to input coercion rules' , ( ) => {
213+ expectValueFrom ( 'null' , testInputObj ) . to . equal ( null ) ;
214+ expectValueFrom ( '123' , testInputObj ) . to . equal ( undefined ) ;
215+ expectValueFrom ( '[]' , testInputObj ) . to . equal ( undefined ) ;
216+ expectValueFrom (
217+ '{ int: 123, requiredBool: false }' ,
218+ testInputObj ,
219+ ) . to . deep . equal ( {
220+ int : 123 ,
221+ requiredBool : false ,
222+ } ) ;
223+ expectValueFrom (
224+ '{ bool: true, requiredBool: false }' ,
225+ testInputObj ,
226+ ) . to . deep . equal ( {
227+ int : 42 ,
228+ bool : true ,
229+ requiredBool : false ,
230+ } ) ;
231+ expectValueFrom ( '{ int: true, requiredBool: true }' , testInputObj ) . to . equal (
232+ undefined ,
233+ ) ;
234+ expectValueFrom ( '{ requiredBool: null }' , testInputObj ) . to . equal ( undefined ) ;
235+ expectValueFrom ( '{ bool: true }' , testInputObj ) . to . equal ( undefined ) ;
236+ } ) ;
237+
238+ it ( 'accepts variable values assuming already coerced' , ( ) => {
239+ expectValueFrom ( '$var' , GraphQLBoolean , { } ) . to . equal ( undefined ) ;
240+ expectValueFrom ( '$var' , GraphQLBoolean , { var : true } ) . to . equal ( true ) ;
241+ expectValueFrom ( '$var' , GraphQLBoolean , { var : null } ) . to . equal ( null ) ;
242+ expectValueFrom ( '$var' , nonNullBool , { var : null } ) . to . equal ( undefined ) ;
243+ } ) ;
244+
245+ it ( 'asserts variables are provided as items in lists' , ( ) => {
246+ expectValueFrom ( '[ $foo ]' , listOfBool , { } ) . to . deep . equal ( [ null ] ) ;
247+ expectValueFrom ( '[ $foo ]' , listOfNonNullBool , { } ) . to . equal ( undefined ) ;
248+ expectValueFrom ( '[ $foo ]' , listOfNonNullBool , {
249+ foo : true ,
250+ } ) . to . deep . equal ( [ true ] ) ;
251+ // Note: variables are expected to have already been coerced, so we
252+ // do not expect the singleton wrapping behavior for variables.
253+ expectValueFrom ( '$foo' , listOfNonNullBool , { foo : true } ) . to . equal ( true ) ;
254+ expectValueFrom ( '$foo' , listOfNonNullBool , { foo : [ true ] } ) . to . deep . equal ( [
255+ true ,
256+ ] ) ;
257+ } ) ;
258+
259+ it ( 'omits input object fields for unprovided variables' , ( ) => {
260+ expectValueFrom (
261+ '{ int: $foo, bool: $foo, requiredBool: true }' ,
262+ testInputObj ,
263+ { } ,
264+ ) . to . deep . equal ( { int : 42 , requiredBool : true } ) ;
265+
266+ expectValueFrom ( '{ requiredBool: $foo }' , testInputObj , { } ) . to . equal (
267+ undefined ,
268+ ) ;
269+
270+ expectValueFrom ( '{ requiredBool: $foo }' , testInputObj , {
271+ foo : true ,
272+ } ) . to . deep . equal ( {
273+ int : 42 ,
274+ requiredBool : true ,
275+ } ) ;
276+ } ) ;
24277} ) ;
0 commit comments