Как тестировать запросы GraphQL с фрагментами с помощью jest

Проблема: я хотел бы протестировать запрос GraphQL, который находится в файле .graphql следующим образом:

#import '../../fragments/Widget.graphql'

query WidgetFragment($id: ID) {
    readWidgetFragment(id: $id) {
        ...Widget
    }
}

Чтобы создать схему GraphQL с имитацией распознавателей и данных, я использую makeExecutableSchema и addMockFunctionsToSchema из graphql-tools. .

Насколько я понимаю, чтобы выполнить запрос из шутливого теста, мне нужно использовать функцию graphql() из graphql-js.

Этой функции нужен запрос в виде строки, поэтому я попробовал два разных способа, но ни один из них не сработал:

  • Разберите файл .graphql как обычный текстовый файл, предоставив мне необработанную строку (используя jest-raw- загрузчик в моей конфигурации jest). Это дает мне: Failed: Errors in query: Unknown fragment "Widget". когда я запускаю запрос.
  • Преобразуйте файл .graphql в объект query, используя jest-transform-graphql. Я считаю, что это должен быть правильный подход, потому что он должен корректно разрешать любые импортированные фрагменты. Однако для выполнения запроса мне нужно передать query.loc.source.body в graphql, что приводит к тому же сообщению об ошибке, что и вариант 1.

person Thomas Zimmermann    schedule 31.05.2018    source источник


Ответы (3)


Вы можете использовать это:

import { print } from 'graphql/language/printer'

import query from './query.gql'

...

print(query)
person tommyboy    schedule 19.12.2018

Используйте первоначальный подход с разбором его как необработанного текста, за исключением:

  1. используйте рекурсивную функцию с аргументом пути (при условии, что у вас могут быть вложенные фрагменты)
  2. который использует regex для предварительного извлечения всего импорта в массив (может быть, используйте более удобный шаблон :))
  3. добавить остальную часть файла к строковой переменной
  4. затем прокручивайте импорт, разрешая #imports и передавая их себе и добавляя результат к строковой переменной
  5. Наконец, верните результат в основную функцию, где вы передадите его в graphql()
person Milos Grujic    schedule 05.09.2019

Да, это совсем огурец. Даже если импорт работает правильно (>= v2.1.0 для jest-transform-graphql, они добавляются к объекту query.definitions, который полностью игнорируется при вызове graphql с document.loc.source.body в качестве аргумента запроса.

На стороне сервера graphql (function graphqlImpl) реконструирует объект document, используя parse(source), но не будет знать об импортированных определениях фрагментов...

Насколько я могу судить, лучше всего прикреплять фрагменты к источнику запроса перед его отправкой на сервер. Вам нужно явно найти все строки, начинающиеся с #import, и заменить их фактическим текстовым содержимым импортируемого файла graphql.

Ниже приведена функция, которую я использую. (Не проверено на рекурсивные фрагменты)

// Async wrapper around dynamic `import` function
import { importQuery } from "./queries";

const importAndReplace = async (fileToImport, sourceDocument, line) => {
  const doc = await importQuery(fileToImport);
  const targetDocument = (await sourceDocument).replace(line, doc.loc.source.body);
  return targetDocument;
};

// Inspired by `graphql-tag/loader` 
// Uses promises because of async function `importQuery` used
export default async graphqlOperation => {
  const { body } = graphqlOperation.loc.source;
  const lines = body.split(/\r\n|\r|\n/);
  const bodyWithInlineImports = await lines.reduce(
    async (accumulator, line) => {
      await accumulator;
      const lineSplit = line.slice(1).split(" ");

      return line[0] === "#" && lineSplit[0] === "import"
        ? importAndReplace(lineSplit[1].replace(/"/g, ""), accumulator, line)
        : Promise.resolve(accumulator);
    },
    Promise.resolve(body)
  );
  return bodyWithInlineImports;
};

person David Remie    schedule 06.09.2019