UNPKG

codemirror-graphql

Version:
170 lines (153 loc) 5.8 kB
/** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import { GraphQLEnumType, GraphQLInputObjectType, parse } from 'graphql'; import { IHint, IHints } from '../../hint'; import collectVariables from '../../utils/collectVariables'; import { TestSchema } from '../../__tests__/testSchema'; import '../hint'; import '../mode'; function createEditorWithHint(query: string) { return CodeMirror(document.createElement('div'), { mode: 'graphql-variables', hintOptions: { variableToType: query && collectVariables(TestSchema, parse(query)), closeOnUnfocus: false, completeSingle: false, }, }); } function getHintSuggestions( query: string, variables: string, cursor: CodeMirror.Position, ) { const editor = createEditorWithHint(query); return new Promise<IHints | undefined>(resolve => { const graphqlVariablesHint = CodeMirror.hint['graphql-variables']; CodeMirror.hint['graphql-variables'] = (cm, options) => { const result = graphqlVariablesHint(cm, options); resolve(result); CodeMirror.hint['graphql-variables'] = graphqlVariablesHint; return result; }; editor.doc.setValue(variables); editor.doc.setCursor(cursor); editor.execCommand('autocomplete'); }); } function expectSuggestions(source: string[], suggestions?: IHint[]) { const titles = suggestions?.map(suggestion => suggestion.text); expect(titles).toEqual(source); } describe('graphql-variables-hint', () => { it('attaches a GraphQL hint function with correct mode/hint options', () => { const editor = createEditorWithHint('{ f }'); expect(editor.getHelpers(editor.getCursor(), 'hint')).not.toHaveLength(0); }); it('provides correct initial token', async () => { const suggestions = await getHintSuggestions('', '', { line: 0, ch: 0 }); const initialKeywords = ['{']; expectSuggestions(initialKeywords, suggestions?.list); }); it('provides correct field name suggestions', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{ ', { line: 0, ch: 2 }, ); expectSuggestions(['"foo": ', '"bar": '], suggestions?.list); }); it('provides correct variable suggestion indentation', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n ', { line: 1, ch: 2 }, ); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 2, sticky: null }); }); it('provides correct variable completion', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n ba', { line: 1, ch: 4 }, ); expectSuggestions(['"bar": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 4, sticky: null }); }); it('provides correct variable completion with open quote', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n "', { line: 1, ch: 4 }, ); expectSuggestions(['"foo": ', '"bar": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 3, sticky: null }); }); it('provides correct Enum suggestions', async () => { const suggestions = await getHintSuggestions( 'query ($myEnum: TestEnum) { f }', '{\n "myEnum": ', { line: 1, ch: 12 }, ); const TestEnum = TestSchema.getType('TestEnum'); expectSuggestions( (TestEnum as GraphQLEnumType) ?.getValues() .map(value => `"${value.name}"`), suggestions?.list, ); }); it('suggests to open an Input Object', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": ', { line: 1, ch: 13 }, ); expectSuggestions(['{'], suggestions?.list); }); it('provides Input Object fields', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n ', { line: 2, ch: 4 }, ); const TestInput = TestSchema.getType('TestInput'); expectSuggestions( Object.keys((TestInput as GraphQLInputObjectType).getFields()).map( name => `"${name}": `, ), suggestions?.list, ); expect(suggestions?.from).toEqual({ line: 2, ch: 4, sticky: null }); expect(suggestions?.to).toEqual({ line: 2, ch: 4, sticky: null }); }); it('provides correct Input Object field completion', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n bool', { line: 2, ch: 8 }, ); expectSuggestions(['"boolean": ', '"listBoolean": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 2, ch: 4, sticky: null }); expect(suggestions?.to).toEqual({ line: 2, ch: 8, sticky: null }); }); it('provides correct Input Object field value completion', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n "boolean": ', { line: 2, ch: 15 }, ); expectSuggestions(['true', 'false'], suggestions?.list); }); });