Как тестировать запросы GraphQL с фрагментами, используя шутку

Проблема: я хотел бы протестировать запрос 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-loader в моей конфигурации jest). Это дает мне: Failed: Errors in query: Unknown fragment "Widget". когда я запускаю запрос.
  • Разобрать .graphql файл в query объект, используя https://github.com/remind101/jest-transform-graphql. Я считаю, что это должен быть правильный подход, поскольку он должен правильно разрешать любые импортированные фрагменты. Однако для выполнения запроса мне нужно пройти query.loc.source.body к graphql, что приводит к тому же сообщению об ошибке, что и вариант 1.

0 ответов

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

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

import query from './query.gql'

...

print(query)

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

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

Да, это довольно соленый огурец. Даже при правильной работе импорта (>= v2.1.0 для https://github.com/remind101/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;
};

Другие вопросы по тегам