UNPKG

27.7 kBPlain TextView Raw
1import {
2 buildSchema,
3 parse,
4 GraphQLNonNull,
5 GraphQLString,
6 GraphQLEnumType,
7 GraphQLList,
8} from "graphql";
9
10import { loadSchema } from "apollo-codegen-core/lib/loading";
11const schema = loadSchema(
12 require.resolve("../../../../__fixtures__/starwars/schema.json")
13);
14
15import {
16 compileToIR,
17 CompilerOptions,
18 CompilerContext,
19 SelectionSet,
20 Field,
21 Argument,
22} from "apollo-codegen-core/lib/compiler";
23
24import { SwiftAPIGenerator } from "../codeGeneration";
25
26describe("Swift code generation", () => {
27 let generator: SwiftAPIGenerator;
28
29 beforeEach(() => {
30 generator = new SwiftAPIGenerator({});
31 });
32
33 function compile(
34 source: string,
35 options: CompilerOptions = {
36 mergeInFieldsFromFragmentSpreads: true,
37 omitDeprecatedEnumCases: false,
38 }
39 ): CompilerContext {
40 const document = parse(source);
41 const context = compileToIR(schema, document, options);
42 generator.context = context;
43 return context;
44 }
45
46 describe("#classDeclarationForOperation()", () => {
47 it(`should generate a class declaration for a query with variables`, () => {
48 const { operations } = compile(`
49 query HeroName($episode: Episode) {
50 hero(episode: $episode) {
51 name
52 }
53 }
54 `);
55
56 generator.classDeclarationForOperation(
57 operations["HeroName"],
58 false,
59 false
60 );
61
62 expect(generator.output).toMatchSnapshot();
63 });
64
65 it(`should generate a class declaration for a query with fragment spreads`, () => {
66 const { operations } = compile(`
67 query Hero {
68 hero {
69 ...HeroDetails
70 }
71 }
72
73 fragment HeroDetails on Character {
74 name
75 }
76 `);
77
78 generator.classDeclarationForOperation(operations["Hero"], false, false);
79
80 expect(generator.output).toMatchSnapshot();
81 });
82
83 it(`should generate a class declaration for a query with conditional fragment spreads`, () => {
84 const { operations } = compile(`
85 query Hero {
86 hero {
87 ...DroidDetails
88 }
89 }
90
91 fragment DroidDetails on Droid {
92 primaryFunction
93 }
94 `);
95
96 generator.classDeclarationForOperation(operations["Hero"], false, false);
97
98 expect(generator.output).toMatchSnapshot();
99 });
100
101 it("should correctly escape a mutli-line string literal", () => {
102 const { operations } = compile(`
103 mutation CreateReview($episode: Episode) {
104 createReview(episode: $episode, review: {stars: 5, commentary:
105 """
106 Wow!
107 I thought
108 This movie ROCKED!
109 """
110 }) {
111 stars
112 commentary
113 }
114 }
115 `);
116
117 generator.classDeclarationForOperation(operations["CreateReview"]);
118
119 expect(generator.output).toMatchSnapshot();
120 });
121
122 it("should correctly escape a mutli-line string literal with backslashes", () => {
123 const { operations } = compile(`
124 mutation CreateReview($episode: Episode) {
125 createReview(episode: $episode, review: {stars: 5, commentary:
126 """
127 Wow!
128 I thought
129 This movie \\ ROCKED!
130 """
131 }) {
132 stars
133 commentary
134 }
135 }
136 `);
137
138 generator.classDeclarationForOperation(
139 operations["CreateReview"],
140 false,
141 false
142 );
143
144 expect(generator.output).toMatchSnapshot();
145 });
146
147 it(`should generate a class declaration for a query with a fragment spread nested in an inline fragment`, () => {
148 const { operations } = compile(`
149 query Hero {
150 hero {
151 ... on Droid {
152 ...HeroDetails
153 }
154 }
155 }
156
157 fragment HeroDetails on Character {
158 name
159 }
160 `);
161
162 generator.classDeclarationForOperation(operations["Hero"], false, false);
163
164 expect(generator.output).toMatchSnapshot();
165 });
166
167 it(`should generate a class declaration for a mutation with variables`, () => {
168 const { operations } = compile(`
169 mutation CreateReview($episode: Episode) {
170 createReview(episode: $episode, review: { stars: 5, commentary: "Wow!" }) {
171 stars
172 commentary
173 }
174 }
175 `);
176
177 generator.classDeclarationForOperation(operations["CreateReview"]);
178
179 expect(generator.output).toMatchSnapshot();
180 });
181
182 it(`should generate a class declaration with an operationIdentifier property when generateOperationIds is specified`, () => {
183 const { operations } = compile(
184 `
185 query Hero {
186 hero {
187 ...HeroDetails
188 }
189 }
190 fragment HeroDetails on Character {
191 name
192 }
193 `,
194 {
195 generateOperationIds: true,
196 mergeInFieldsFromFragmentSpreads: true,
197 omitDeprecatedEnumCases: false,
198 }
199 );
200
201 generator.classDeclarationForOperation(operations["Hero"], false, false);
202
203 expect(generator.output).toMatchSnapshot();
204 });
205 });
206
207 describe("#initializerDeclarationForProperties()", () => {
208 it(`should generate initializer for a property`, () => {
209 generator.initializerDeclarationForProperties([
210 { propertyName: "episode", typeName: "Episode" },
211 ]);
212
213 expect(generator.output).toMatchSnapshot();
214 });
215
216 it(`should generate initializer for an optional property`, () => {
217 generator.initializerDeclarationForProperties([
218 { propertyName: "episode", typeName: "Episode?", isOptional: true },
219 ]);
220
221 expect(generator.output).toMatchSnapshot();
222 });
223
224 it(`should generate initializer for multiple properties`, () => {
225 generator.initializerDeclarationForProperties([
226 { propertyName: "episode", typeName: "Episode?", isOptional: true },
227 { propertyName: "scene", typeName: "String?", isOptional: true },
228 ]);
229
230 expect(generator.output).toMatchSnapshot();
231 });
232 });
233
234 describe("#propertyAssignmentForField()", () => {
235 it("should generate expression for nullable scalar", () => {
236 expect(
237 generator.propertyAssignmentForField({
238 responseKey: "response_key",
239 propertyName: "propertyName",
240 type: GraphQLString,
241 }).source
242 ).toBe('"response_key": propertyName');
243 });
244
245 it("should generate expression for non-null scalar", () => {
246 expect(
247 generator.propertyAssignmentForField({
248 responseKey: "response_key",
249 propertyName: "propertyName",
250 type: new GraphQLNonNull(GraphQLString),
251 }).source
252 ).toBe('"response_key": propertyName');
253 });
254
255 it("should generate expression for nullable list of nullable scalars", () => {
256 expect(
257 generator.propertyAssignmentForField({
258 responseKey: "response_key",
259 propertyName: "propertyName",
260 type: new GraphQLList(GraphQLString),
261 }).source
262 ).toBe('"response_key": propertyName');
263 });
264
265 it("should generate expression for nullable list of non-null scalars", () => {
266 expect(
267 generator.propertyAssignmentForField({
268 responseKey: "response_key",
269 propertyName: "propertyName",
270 type: new GraphQLList(new GraphQLNonNull(GraphQLString)),
271 }).source
272 ).toBe('"response_key": propertyName');
273 });
274
275 it("should generate expression for non-null list of nullable scalars", () => {
276 expect(
277 generator.propertyAssignmentForField({
278 responseKey: "response_key",
279 propertyName: "propertyName",
280 type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
281 }).source
282 ).toBe('"response_key": propertyName');
283 });
284
285 it("should generate expression for non-null list of non-null scalars", () => {
286 expect(
287 generator.propertyAssignmentForField({
288 responseKey: "response_key",
289 propertyName: "propertyName",
290 type: new GraphQLNonNull(
291 new GraphQLList(new GraphQLNonNull(GraphQLString))
292 ),
293 }).source
294 ).toBe('"response_key": propertyName');
295 });
296
297 it("should generate expression for nullable composite", () => {
298 expect(
299 generator.propertyAssignmentForField({
300 responseKey: "response_key",
301 propertyName: "propertyName",
302 type: schema.getType("Droid"),
303 }).source
304 ).toBe(
305 '"response_key": propertyName.flatMap { (value: Droid) -> ResultMap in value.resultMap }'
306 );
307 });
308
309 it("should generate expression for non-null composite", () => {
310 expect(
311 generator.propertyAssignmentForField({
312 responseKey: "response_key",
313 propertyName: "propertyName",
314 type: new GraphQLNonNull(schema.getType("Droid")),
315 }).source
316 ).toBe('"response_key": propertyName.resultMap');
317 });
318
319 it("should generate expression for nullable list of nullable composites", () => {
320 expect(
321 generator.propertyAssignmentForField({
322 responseKey: "response_key",
323 propertyName: "propertyName",
324 type: new GraphQLList(schema.getType("Droid")),
325 }).source
326 ).toBe(
327 '"response_key": propertyName.flatMap { (value: [Droid?]) -> [ResultMap?] in value.map { (value: Droid?) -> ResultMap? in value.flatMap { (value: Droid) -> ResultMap in value.resultMap } } }'
328 );
329 });
330
331 it("should generate expression for nullable list of non-null composites", () => {
332 expect(
333 generator.propertyAssignmentForField({
334 responseKey: "response_key",
335 propertyName: "propertyName",
336 type: new GraphQLList(new GraphQLNonNull(schema.getType("Droid"))),
337 }).source
338 ).toBe(
339 '"response_key": propertyName.flatMap { (value: [Droid]) -> [ResultMap] in value.map { (value: Droid) -> ResultMap in value.resultMap } }'
340 );
341 });
342
343 it("should generate expression for non-null list of nullable composites", () => {
344 expect(
345 generator.propertyAssignmentForField({
346 responseKey: "response_key",
347 propertyName: "propertyName",
348 type: new GraphQLNonNull(new GraphQLList(schema.getType("Droid"))),
349 }).source
350 ).toBe(
351 '"response_key": propertyName.map { (value: Droid?) -> ResultMap? in value.flatMap { (value: Droid) -> ResultMap in value.resultMap } }'
352 );
353 });
354
355 it("should generate expression for non-null list of non-null composites", () => {
356 expect(
357 generator.propertyAssignmentForField({
358 responseKey: "response_key",
359 propertyName: "propertyName",
360 type: new GraphQLNonNull(
361 new GraphQLList(new GraphQLNonNull(schema.getType("Droid")))
362 ),
363 }).source
364 ).toBe(
365 '"response_key": propertyName.map { (value: Droid) -> ResultMap in value.resultMap }'
366 );
367 });
368 });
369
370 describe("#propertyDeclarationForField()", () => {
371 it(`should generate structName as testCTum for key testCTA`, () => {
372 // The existing schemas don't contain any outputs with fields ending in a series of caps,
373 // while also being a composite type.
374 const schema = buildSchema(`
375 schema {
376 query: Query
377 }
378 type Query {
379 foo(input: FooInput!): FooOutput
380 }
381 input FooInput {
382 id: ID
383 }
384 type FooOutput {
385 testCTA: Link
386 }
387 union Link = InternalLink | ExternalLink
388 type InternalLink {
389 path: String
390 }
391 type ExternalLink {
392 url: String
393 }
394 `);
395 const document = parse(`
396 query Test {
397 foo(input: {}) {
398 testCTA {
399 ... on InternalLink {
400 path
401 }
402 ... on ExternalLink {
403 url
404 }
405 }
406 }
407 }
408 `);
409 const context = compileToIR(schema, document);
410 generator.context = context;
411
412 const { operations, typesUsed } = context;
413
414 const outputField = operations["Test"].selectionSet
415 .selections[0] as Field;
416 generator.propertyDeclarationForField(
417 outputField.selectionSet.selections[0] as Field & Property
418 );
419
420 expect(generator.output).toMatchSnapshot();
421 });
422 });
423
424 describe("#structDeclarationForFragment()", () => {
425 it(`should generate a struct declaration for a fragment with an abstract type condition`, () => {
426 const { fragments } = compile(`
427 fragment HeroDetails on Character {
428 name
429 appearsIn
430 }
431 `);
432
433 generator.structDeclarationForFragment(fragments["HeroDetails"], false);
434
435 expect(generator.output).toMatchSnapshot();
436 });
437
438 it(`should generate a struct declaration for a fragment with a concrete type condition`, () => {
439 const { fragments } = compile(`
440 fragment DroidDetails on Droid {
441 name
442 primaryFunction
443 }
444 `);
445
446 generator.structDeclarationForFragment(
447 fragments["DroidDetails"],
448 false,
449 false
450 );
451
452 expect(generator.output).toMatchSnapshot();
453 });
454
455 it(`should generate a struct declaration for a fragment with a subselection`, () => {
456 const { fragments } = compile(`
457 fragment HeroDetails on Character {
458 name
459 friends {
460 name
461 }
462 }
463 `);
464
465 generator.structDeclarationForFragment(
466 fragments["HeroDetails"],
467 false,
468 false
469 );
470
471 expect(generator.output).toMatchSnapshot();
472 });
473
474 it(`should generate a struct declaration for a fragment that includes a fragment spread`, () => {
475 const { fragments } = compile(`
476 fragment HeroDetails on Character {
477 name
478 ...MoreHeroDetails
479 }
480
481 fragment MoreHeroDetails on Character {
482 appearsIn
483 }
484 `);
485
486 generator.structDeclarationForFragment(
487 fragments["HeroDetails"],
488 false,
489 false
490 );
491
492 expect(generator.output).toMatchSnapshot();
493 });
494 });
495
496 describe("#structDeclarationForSelectionSet()", () => {
497 it(`should generate a struct declaration for a selection set`, () => {
498 const { operations } = compile(`
499 query Hero {
500 hero {
501 name
502 }
503 }
504 `);
505
506 const selectionSet = (
507 operations["Hero"].selectionSet.selections[0] as Field
508 ).selectionSet as SelectionSet;
509
510 generator.structDeclarationForSelectionSet(
511 {
512 structName: "Hero",
513 selectionSet,
514 },
515 false
516 );
517
518 expect(generator.output).toMatchSnapshot();
519 });
520
521 it(`should preserve leading and trailing underscores on fields`, () => {
522 const { operations } = compile(`
523 query Hero {
524 hero {
525 _name: name
526 _camel_case_id__: id
527 }
528 }
529 `);
530
531 const selectionSet = (
532 operations["Hero"].selectionSet.selections[0] as Field
533 ).selectionSet as SelectionSet;
534
535 generator.structDeclarationForSelectionSet(
536 {
537 structName: "Hero",
538 selectionSet,
539 },
540 false
541 );
542
543 expect(generator.output).toMatchSnapshot();
544 });
545
546 it(`should escape reserved keywords in a struct declaration for a selection set`, () => {
547 const { operations } = compile(`
548 query Hero {
549 hero {
550 private: name
551 self: friends {
552 id
553 }
554 }
555 }
556 `);
557
558 const selectionSet = (
559 operations["Hero"].selectionSet.selections[0] as Field
560 ).selectionSet as SelectionSet;
561
562 generator.structDeclarationForSelectionSet(
563 {
564 structName: "Hero",
565 selectionSet,
566 },
567 false
568 );
569
570 expect(generator.output).toMatchSnapshot();
571 });
572
573 it(`should escape init specially in a struct declaration initializer for a selection set`, () => {
574 const { operations } = compile(`
575 query Humans {
576 human(id: 0) {
577 self: friends {
578 id
579 }
580 }
581 human(id: 1) {
582 self: friends {
583 id
584 }
585 _self: name
586 }
587 }
588 `);
589
590 const human0 = (operations["Humans"].selectionSet.selections[0] as Field)
591 .selectionSet as SelectionSet;
592 const human1 = (operations["Humans"].selectionSet.selections[1] as Field)
593 .selectionSet as SelectionSet;
594
595 generator.structDeclarationForSelectionSet(
596 {
597 structName: "Human",
598 selectionSet: human0,
599 },
600 false
601 );
602 generator.structDeclarationForSelectionSet(
603 {
604 structName: "Human",
605 selectionSet: human1,
606 },
607 false
608 );
609
610 expect(generator.output).toMatchSnapshot();
611 });
612
613 it(`should generate a nested struct declaration for a selection set with subselections`, () => {
614 const { operations } = compile(`
615 query Hero {
616 hero {
617 friends {
618 name
619 }
620 }
621 }
622 `);
623
624 const selectionSet = (
625 operations["Hero"].selectionSet.selections[0] as Field
626 ).selectionSet as SelectionSet;
627
628 generator.structDeclarationForSelectionSet(
629 {
630 structName: "Hero",
631 selectionSet,
632 },
633 false
634 );
635
636 expect(generator.output).toMatchSnapshot();
637 });
638
639 it(`should generate a struct declaration for a selection set with a fragment spread that matches the parent type`, () => {
640 const { operations } = compile(`
641 query Hero {
642 hero {
643 name
644 ...HeroDetails
645 }
646 }
647
648 fragment HeroDetails on Character {
649 name
650 }
651 `);
652
653 const selectionSet = (
654 operations["Hero"].selectionSet.selections[0] as Field
655 ).selectionSet as SelectionSet;
656
657 generator.structDeclarationForSelectionSet(
658 {
659 structName: "Hero",
660 selectionSet,
661 },
662 false
663 );
664
665 expect(generator.output).toMatchSnapshot();
666 });
667
668 it(`should generate a struct declaration for a selection set with a fragment spread with a more specific type condition`, () => {
669 const { operations } = compile(`
670 query Hero {
671 hero {
672 name
673 ...DroidDetails
674 }
675 }
676
677 fragment DroidDetails on Droid {
678 name
679 }
680 `);
681
682 const selectionSet = (
683 operations["Hero"].selectionSet.selections[0] as Field
684 ).selectionSet as SelectionSet;
685
686 generator.structDeclarationForSelectionSet(
687 {
688 structName: "Hero",
689 selectionSet,
690 },
691 false
692 );
693
694 expect(generator.output).toMatchSnapshot();
695 });
696
697 it(`should generate a struct declaration for a selection set with an inline fragment`, () => {
698 const { operations } = compile(`
699 query Hero {
700 hero {
701 name
702 ... on Droid {
703 primaryFunction
704 }
705 }
706 }
707 `);
708
709 const selectionSet = (
710 operations["Hero"].selectionSet.selections[0] as Field
711 ).selectionSet as SelectionSet;
712
713 generator.structDeclarationForSelectionSet(
714 {
715 structName: "Hero",
716 selectionSet,
717 },
718 false
719 );
720
721 expect(generator.output).toMatchSnapshot();
722 });
723
724 it(`should generate a struct declaration for a fragment spread nested in an inline fragment`, () => {
725 const { operations } = compile(`
726 query Hero {
727 hero {
728 name
729 ... on Droid {
730 ...HeroDetails
731 }
732 }
733 }
734
735 fragment HeroDetails on Character {
736 name
737 }
738 `);
739
740 const selectionSet = (
741 operations["Hero"].selectionSet.selections[0] as Field
742 ).selectionSet as SelectionSet;
743
744 generator.structDeclarationForSelectionSet(
745 {
746 structName: "Hero",
747 selectionSet,
748 },
749 false
750 );
751
752 expect(generator.output).toMatchSnapshot();
753 });
754
755 it(`should generate a struct declaration for a selection set with a conditional field`, () => {
756 const { operations } = compile(`
757 query Hero($includeName: Boolean!) {
758 hero {
759 name @include(if: $includeName)
760 }
761 }
762 `);
763
764 const selectionSet = (
765 operations["Hero"].selectionSet.selections[0] as Field
766 ).selectionSet as SelectionSet;
767
768 generator.structDeclarationForSelectionSet(
769 {
770 structName: "Hero",
771 selectionSet,
772 },
773 false
774 );
775
776 expect(generator.output).toMatchSnapshot();
777 });
778 });
779
780 describe("#typeDeclarationForGraphQLType()", () => {
781 it("should generate an enum declaration for a GraphQLEnumType", () => {
782 generator.typeDeclarationForGraphQLType(schema.getType("Episode"), false);
783
784 expect(generator.output).toMatchSnapshot();
785 });
786
787 it("should escape identifiers in cases of enum declaration for a GraphQLEnumType", () => {
788 const albumPrivaciesEnum = new GraphQLEnumType({
789 name: "AlbumPrivacies",
790 values: { PUBLIC: { value: "PUBLIC" }, PRIVATE: { value: "PRIVATE" } },
791 });
792
793 generator.typeDeclarationForGraphQLType(albumPrivaciesEnum, false);
794
795 expect(generator.output).toMatchSnapshot();
796 });
797
798 it("should omit deprecated cases from an enum declaration for a GraphQLEnumType", () => {
799 const { operations } = compile(
800 `
801 query Starship {
802 starship(id: 1) {
803 length(unit: METER)
804 }
805 }
806 `,
807 {
808 generateOperationIds: true,
809 mergeInFieldsFromFragmentSpreads: true,
810 omitDeprecatedEnumCases: true,
811 }
812 );
813
814 let starship = operations["Starship"].selectionSet.selections[0] as Field;
815 let starshipLength = starship.selectionSet.selections[0] as Field;
816 let lengthUnitArg = starshipLength.args[0].type;
817
818 generator.typeDeclarationForGraphQLType(lengthUnitArg, false);
819
820 expect(generator.output).toMatchSnapshot();
821 });
822
823 it("should include deprecated cases in an enum declaration for a GraphQLEnumType", () => {
824 const { operations } = compile(`
825 query Starship {
826 starship(id: 1) {
827 length(unit: METER)
828 }
829 }
830 `);
831
832 let starship = operations["Starship"].selectionSet.selections[0] as Field;
833 let starshipLength = starship.selectionSet.selections[0] as Field;
834 let lengthUnitArg = starshipLength.args[0].type;
835
836 generator.typeDeclarationForGraphQLType(lengthUnitArg, false);
837
838 expect(generator.output).toMatchSnapshot();
839 });
840
841 it("should generate a struct declaration for a GraphQLInputObjectType", () => {
842 generator.typeDeclarationForGraphQLType(
843 schema.getType("ReviewInput"),
844 false
845 );
846
847 expect(generator.output).toMatchSnapshot();
848 });
849 });
850
851 describe("#dictionaryLiteralForFieldArguments()", () => {
852 it("should include expressions for input objects with variables", () => {
853 const { operations } = compile(`
854 mutation FieldArgumentsWithInputObjects($commentary: String!, $red: Int!) {
855 createReview(episode: JEDI, review: { stars: 2, commentary: $commentary, favorite_color: { red: $red, blue: 100, green: 50 } }) {
856 commentary
857 }
858 }
859 `);
860
861 const fieldArguments = (
862 operations["FieldArgumentsWithInputObjects"].selectionSet
863 .selections[0] as Field
864 ).args as Argument[];
865 const dictionaryLiteral =
866 generator.helpers.dictionaryLiteralForFieldArguments(
867 fieldArguments
868 ).source;
869
870 expect(dictionaryLiteral).toBe(
871 '["episode": "JEDI", "review": ["stars": 2, "commentary": GraphQLVariable("commentary"), "favorite_color": ["red": GraphQLVariable("red"), "blue": 100, "green": 50]]]'
872 );
873 });
874
875 it("should handle empty input objects", () => {
876 // The existing schemas don't contain any input objects with all nullable types.
877 // Extending the schema in a call to `compile` doesn't seem to work.
878 // So instead we'll just build our own.
879 const schema = buildSchema(`
880 schema {
881 query: Query
882 }
883 type Query {
884 foo(input: FooInput!): Int
885 }
886 input FooInput {
887 id: ID
888 }
889 `);
890 const document = parse(`
891 query FieldArgumentsWithEmptyInputObject {
892 foo(input: {}) {
893 id
894 }
895 }
896 `);
897 const context = compileToIR(schema, document);
898 generator.context = context;
899
900 const { operations } = context;
901 const fieldArguments = (
902 operations["FieldArgumentsWithEmptyInputObject"].selectionSet
903 .selections[0] as Field
904 ).args as Argument[];
905 const dictionaryLiteral =
906 generator.helpers.dictionaryLiteralForFieldArguments(
907 fieldArguments
908 ).source;
909
910 expect(dictionaryLiteral).toBe('["input": [:]]');
911 });
912
913 it("should handle empty input arrays", () => {
914 // As with the previous test, we need to build our own schema.
915 const schema = buildSchema(`
916 schema {
917 query: Query
918 }
919 type Query {
920 foo(input: [Int!]!): Int
921 }
922 `);
923 const document = parse(`
924 query FieldArgumentsWithEmptyInputArray {
925 foo(input: []) {
926 id
927 }
928 }
929 `);
930 const context = compileToIR(schema, document);
931 generator.context = context;
932
933 const { operations } = context;
934 const fieldArguments = (
935 operations["FieldArgumentsWithEmptyInputArray"].selectionSet
936 .selections[0] as Field
937 ).args as Argument[];
938 const dictionaryLiteral =
939 generator.helpers.dictionaryLiteralForFieldArguments(
940 fieldArguments
941 ).source;
942
943 expect(dictionaryLiteral).toBe('["input": []]');
944 });
945
946 it("should handle input fields of various scalar types including null", () => {
947 // As with the previous test, we need to build our own schema.
948 const schema = buildSchema(`
949 schema {
950 query: Query
951 }
952 type Query {
953 foo(input: FooInput!): Int
954 }
955 input FooInput {
956 id: ID
957 id2: ID
958 name: String
959 age: Int
960 rating: Float
961 bool: Boolean
962 }
963 `);
964 const document = parse(`
965 query FieldArgumentsWithVariousScalars {
966 foo(input: { id: null, id2: "4", name: "Anne", age: 27, rating: 4.7, bool: true }) {
967 id
968 }
969 }
970 `);
971 const context = compileToIR(schema, document);
972 generator.context = context;
973
974 const { operations } = context;
975 const fieldArguments = (
976 operations["FieldArgumentsWithVariousScalars"].selectionSet
977 .selections[0] as Field
978 ).args as Argument[];
979 const dictionaryLiteral =
980 generator.helpers.dictionaryLiteralForFieldArguments(
981 fieldArguments
982 ).source;
983
984 expect(dictionaryLiteral).toBe(
985 '["input": ["id": nil, "id2": "4", "name": "Anne", "age": 27, "rating": 4.7, "bool": true]]'
986 );
987 });
988 });
989});