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

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

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

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

Чтобы создать схему GraphQL с имитируемыми преобразователями и данными, я использую makeExecutableSchema и addMockFunctionsToSchema из графические инструменты.

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

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

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

Ответы 3

Ответ принят как подходящий

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

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

import query from './query.gql'

...

print(query)

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

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

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

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