Mirror: The spec-compliant minimum of client-side GraphQL.
1import { describe, it, expect } from 'vitest'; 2import { readFileSync } from 'fs'; 3 4import { parse, print as graphql_print } from 'graphql'; 5import { print, printString, printBlockString } from '../printer'; 6 7function dedentString(string) { 8 const trimmedStr = string 9 .replace(/^\n*/m, '') // remove leading newline 10 .replace(/[ \t\n]*$/, ''); // remove trailing spaces and tabs 11 // fixes indentation by removing leading spaces and tabs from each line 12 let indent = ''; 13 for (const char of trimmedStr) { 14 if (char !== ' ' && char !== '\t') { 15 break; 16 } 17 indent += char; 18 } 19 20 return trimmedStr.replace(RegExp('^' + indent, 'mg'), ''); // remove indent 21} 22 23function dedent(strings, ...values) { 24 let str = strings[0]; 25 for (let i = 1; i < strings.length; ++i) str += values[i - 1] + strings[i]; // interpolation 26 return dedentString(str); 27} 28 29describe('printString', () => { 30 it('prints strings as expected', () => { 31 expect(printString('test')).toEqual('"test"'); 32 expect(printString('\n')).toEqual('"\\n"'); 33 }); 34}); 35 36describe('printBlockString', () => { 37 it('prints block strings as expected', () => { 38 expect(printBlockString('test')).toEqual('"""\ntest\n"""'); 39 expect(printBlockString('\n')).toEqual('"""\n\n\n"""'); 40 expect(printBlockString('"""')).toEqual('"""\n\\"""\n"""'); 41 }); 42}); 43 44describe('print', () => { 45 it('prints the kitchen sink document like graphql.js does', () => { 46 const sink = JSON.parse(readFileSync(__dirname + '/kitchen_sink.json', { encoding: 'utf8' })); 47 const doc = print(sink); 48 expect(doc).toMatchSnapshot(); 49 expect(doc).toEqual(graphql_print(sink)); 50 }); 51 52 it('prints minimal ast', () => { 53 expect( 54 print({ 55 kind: 'Field', 56 name: { kind: 'Name', value: 'foo' }, 57 } as any) 58 ).toBe('foo'); 59 60 expect( 61 print({ 62 kind: 'Name', 63 value: 'foo', 64 } as any) 65 ).toBe('foo'); 66 67 expect( 68 print({ 69 kind: 'Document', 70 definitions: [], 71 } as any) 72 ).toBe(''); 73 }); 74 75 it('prints integers and floats', () => { 76 expect( 77 print({ 78 kind: 'IntValue', 79 value: '12', 80 } as any) 81 ).toBe('12'); 82 83 expect( 84 print({ 85 kind: 'FloatValue', 86 value: '12e2', 87 } as any) 88 ).toBe('12e2'); 89 }); 90 91 it('prints lists of values', () => { 92 expect( 93 print({ 94 kind: 'ListValue', 95 values: [{ kind: 'NullValue' }], 96 } as any) 97 ).toBe('[null]'); 98 }); 99 100 it('prints types', () => { 101 expect( 102 print({ 103 kind: 'ListType', 104 type: { 105 kind: 'NonNullType', 106 type: { 107 kind: 'NamedType', 108 name: { 109 kind: 'Name', 110 value: 'Type', 111 }, 112 }, 113 }, 114 } as any) 115 ).toBe('[Type!]'); 116 }); 117 118 // NOTE: The shim won't throw for invalid AST nodes 119 it('returns empty strings for invalid AST', () => { 120 const badAST = { random: 'Data' }; 121 expect(print(badAST as any)).toBe(''); 122 }); 123 124 it('correctly prints non-query operations without name', () => { 125 const queryASTShorthanded = parse('query { id, name }'); 126 expect(print(queryASTShorthanded)).toBe(dedent` 127 { 128 id 129 name 130 } 131 `); 132 133 const mutationAST = parse('mutation { id, name }'); 134 expect(print(mutationAST)).toBe(dedent` 135 mutation { 136 id 137 name 138 } 139 `); 140 141 const queryASTWithArtifacts = parse('query ($foo: TestType) @testDirective { id, name }'); 142 expect(print(queryASTWithArtifacts)).toBe(dedent` 143 query ($foo: TestType) @testDirective { 144 id 145 name 146 } 147 `); 148 149 const mutationASTWithArtifacts = parse('mutation ($foo: TestType) @testDirective { id, name }'); 150 expect(print(mutationASTWithArtifacts)).toBe(dedent` 151 mutation ($foo: TestType) @testDirective { 152 id 153 name 154 } 155 `); 156 }); 157 158 it('prints query with variable directives', () => { 159 const queryASTWithVariableDirective = parse( 160 'query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id }' 161 ); 162 expect(print(queryASTWithVariableDirective)).toBe(dedent` 163 query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { 164 id 165 } 166 `); 167 }); 168 169 it('keeps arguments on one line if line is short (<= 80 chars)', () => { 170 const printed = print(parse('{trip(wheelchair:false arriveBy:false){dateTime}}')); 171 172 expect(printed).toBe( 173 dedent` 174 { 175 trip(wheelchair: false, arriveBy: false) { 176 dateTime 177 } 178 } 179 ` 180 ); 181 }); 182});