Reputation: 101
Problem: I would like to test a GraphQL query that lives in a .graphql
file like this:
#import '../../fragments/Widget.graphql'
query WidgetFragment($id: ID) {
readWidgetFragment(id: $id) {
...Widget
}
}
To create a GraphQL schema with mocked resolvers and data, I use makeExecutableSchema
and addMockFunctionsToSchema
from graphql-tools.
To run the query from inside a jest test, my understanding is that I need to use the graphql()
function from graphql-js.
This function needs the query as a string, so I tried two different ways, but neither of them worked:
.graphql
file as a normal text file, giving me the raw string (using the jest-raw-loader in my jest config).
This gives me: Failed: Errors in query: Unknown fragment "Widget".
when I run the query..graphql
file into a query
object using jest-transform-graphql. I believe this should be the right approach, because it should resolve any imported fragments properly. However, to execute the query, I need to pass query.loc.source.body
to the graphql
, which results in the same error message as option 1.Upvotes: 5
Views: 2918
Reputation: 1077
Yes, this is quite a pickle. Even with imports correctly working (>= v2.1.0 for jest-transform-graphql, they get added to the query.definitions
object, which is completely sidestepped when calling graphql
with document.loc.source.body
as query argument.
On the server end, graphql (function graphqlImpl
) will reconstruct the document
object using parse(source)
- but it'll have zero knowledge of the imported fragment definitions...
As far as I can tell, the best bet is to stamp fragments to the query source before sending it to the server. You'll need to explicitly find all lines starting with #import
and replace these with actual text content of the to-be-imported graphql
file.
Below is the function that I use. (Not tested for recursive fragments)
// 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;
};
Upvotes: 0
Reputation: 584
Use the initial approach with parsing it as a raw text, except:
#import
s and passing them to itself and appending the result to the string variablegraphql()
Upvotes: 0
Reputation: 56
You can use this:
import { print } from 'graphql/language/printer'
import query from './query.gql'
...
print(query)
Upvotes: 4