Как тестировать запросы 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)
Используйте первоначальный подход с анализом его как необработанного текста, за исключением:
- используйте рекурсивную функцию с аргументом пути (при условии, что у вас могут быть вложенные фрагменты)
- который использует регулярное выражение для предварительного извлечения всего импорта в массив (возможно, используйте более красивый шаблон:))
- добавить остальную часть файла в строковую переменную
- затем переберите импорт, разрешив
#import
s и передавая их себе и добавляя результат к строковой переменной - Наконец, верните результат в основную функцию, где вы передадите его в
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;
};